<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Gerard Hynes - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Gerard Hynes - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 19 May 2026 22:44:46 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/gerardhynes/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ The Apache Kafka Handbook – How to Get Started Using Kafka ]]>
                </title>
                <description>
                    <![CDATA[ Apache Kafka is an open-source event streaming platform that can transport huge volumes of data at very low latency. Companies like LinkedIn, Uber, and Netflix use Kafka to process trillions of events and petabtyes of data each day. Kafka was origina... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/apache-kafka-handbook/</link>
                <guid isPermaLink="false">66d45edb787a2a3b05af43a0</guid>
                
                    <category>
                        <![CDATA[ Apache Kafka ]]>
                    </category>
                
                    <category>
                        <![CDATA[ big data ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gerard Hynes ]]>
                </dc:creator>
                <pubDate>Fri, 03 Feb 2023 23:48:22 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/apache-kafka-handbook.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Apache Kafka is an open-source event streaming platform that can transport huge volumes of data at very low latency.</p>
<p>Companies like LinkedIn, Uber, and Netflix use Kafka to process trillions of events and petabtyes of data each day.</p>
<p>Kafka was <a target="_blank" href="https://engineering.linkedin.com/27/project-kafka-distributed-publish-subscribe-messaging-system-reaches-v06">originally developed at LinkedIn</a>, to help handle their real-time data feeds. It's now maintained by the <a target="_blank" href="https://kafka.apache.org/">Apache Software Foundation</a>, and is widely adopted in industry (being used by 80% of Fortune 100 companies).</p>
<h2 id="heading-why-should-you-learn-apache-kafka">Why Should You Learn Apache Kafka?</h2>
<p>Kafka lets you:</p>
<ul>
<li><p>Publish and subscribe to streams of events</p>
</li>
<li><p>Store streams of events in the same order they happened</p>
</li>
<li><p>Process streams of events in real time</p>
</li>
</ul>
<p>The main thing Kafka does is help you efficiently connect diverse data sources with the many different systems that might need to use that data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/before-and-after-kafka-1.PNG" alt="Messy data integrations without Kafka, more organized data integrations with Kafka." width="600" height="400" loading="lazy"></p>
<p><em>Kafka helps you connect data sources to the systems using that data</em></p>
<p>Some of the things you can use Kafka for include:</p>
<ul>
<li><p>Personalizing recommendations for customers</p>
</li>
<li><p>Notifying passengers of flight delays</p>
</li>
<li><p>Payment processing in banking</p>
</li>
<li><p>Online fraud detection</p>
</li>
<li><p>Managing inventory and supply chains</p>
</li>
<li><p>Tracking order shipments</p>
</li>
<li><p>Collecting telemetry data from Internet of Things (IoT) devices</p>
</li>
</ul>
<p>What all these uses have in common is that they need to take in and process data in real time, often at huge scales. This is something Kafka excels at. To give one example, <a target="_blank" href="https://www.confluent.io/blog/running-kafka-at-scale-at-pinterest/">Pinterest uses Kafka to handle up to 40 million events per second</a>.</p>
<p>Kafka is distributed, which means it runs as a cluster of nodes spread across multiple servers. It's also replicated, meaning that data is copied in multiple locations to protect it from a single point of failure. This makes Kafka both scalable and fault-tolerant.</p>
<p>Kafka is also fast. It's optimized for high throughput, making effective use of disk storage and batched network requests.</p>
<p>This article will:</p>
<ul>
<li><p>Introduce you to the core concepts behind Kafka</p>
</li>
<li><p>Show you how to install Kafka on your own computer</p>
</li>
<li><p>Get you started with the Kafka Command Line Interface (CLI)</p>
</li>
<li><p>Help you build a simple Java application that produces and consumes events via Kafka</p>
</li>
</ul>
<p>Things the article won't cover:</p>
<ul>
<li><p>More advanced Kafka topics, such as security, performance, and monitoring</p>
</li>
<li><p>Deploying a Kafka cluster to a server</p>
</li>
<li><p>Using managed Kafka services like Amazon MSK or Confluent Cloud</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-event-streaming-and-event-driven-architectures">Event Streaming and Event-Driven Architectures</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-core-kafka-concepts">Core Kafka Concepts</a><br> a. <a class="post-section-overview" href="#heading-event-messages-in-kafka">Event Messages in Kafka</a><br> b. <a class="post-section-overview" href="#heading-topics-in-kafka">Topics in Kafka</a><br> c. <a class="post-section-overview" href="#heading-partitions-in-kafka">Partitions in Kafka</a><br> d. <a class="post-section-overview" href="#heading-offsets-in-kafka">Offsets in Kafka</a><br> e. <a class="post-section-overview" href="#heading-brokers-in-kafka">Brokers in Kafka</a><br> f. <a class="post-section-overview" href="#heading-replication-in-kafka">Replication in Kafka</a><br> g. <a class="post-section-overview" href="#heading-producers-in-kafka">Producers in Kafka</a><br> h. <a class="post-section-overview" href="#heading-consumers-in-kafka">Consumers in Kafka</a><br> i. <a class="post-section-overview" href="#heading-consumer-groups-in-kafka">Consumer Groups in Kafka</a><br> j. <a class="post-section-overview" href="#heading-kafka-zookeeper">Kafka Zookeeper</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-install-kafka-on-your-computer">How to Install Kafka on Your Computer</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-start-zookeeper-and-kafka">How to Start Zookeeper and Kafka</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-kafka-cli">The Kafka CLI</a><br> a. <a class="post-section-overview" href="#heading-how-to-list-topics">How to List Topics</a><br> b. <a class="post-section-overview" href="#heading-how-to-create-a-topic">How to Create a Topic</a><br> c. <a class="post-section-overview" href="#heading-how-to-describe-topics">How to Describe Topics</a><br> d. <a class="post-section-overview" href="#heading-how-to-partition-a-topic">How to Partition a Topic</a><br> e. <a class="post-section-overview" href="#heading-how-to-set-a-replication-factor">How to Set a Replication Factor</a><br> f. <a class="post-section-overview" href="#heading-how-to-delete-a-topic">How to Delete a Topic</a><br> g. <a class="post-section-overview" href="#heading-how-to-use-kafka-console-producer">How to use <code>kafka-console-producer</code></a><br> h. <a class="post-section-overview" href="#heading-how-to-use-kafka-console-consumer">How to use <code>kafka-console-consumer</code></a><br> i. <a class="post-section-overview" href="#heading-how-to-use-kafka-consumer-groups">How to use <code>kafka-consumer-groups</code></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-kafka-client-app-with-java">How to Build a Kafka Client App with Java</a><br> a. <a class="post-section-overview" href="#heading-how-to-set-up-the-project">How to Set Up the Project</a><br> b. <a class="post-section-overview" href="#heading-how-to-install-the-dependencies">How to Install the Dependencies</a><br> c. <a class="post-section-overview" href="#heading-how-to-create-a-kafka-producer">How to Create a Kafka Producer</a><br> d. <a class="post-section-overview" href="#heading-how-to-send-multiple-messages-and-use-callbacks">How to Send Multiple Messages and Use Callbacks</a><br> e. <a class="post-section-overview" href="#heading-how-to-create-a-kafka-consumer">How to Create a Kafka Consumer</a><br> f. <a class="post-section-overview" href="#heading-how-to-shut-down-the-consumer">How to Shut Down the Consumer</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-where-to-take-it-from-here">Where to Take it From Here</a></p>
</li>
</ol>
<p>Before we dive into Kafka, we need some context on event streaming and event-driven architectures.</p>
<h2 id="heading-event-streaming-and-event-driven-architectures">Event Streaming and Event-Driven Architectures</h2>
<p>An event is a record that something happened, as well as information about what happened. For example: a customer placed an order, a bank approved a transaction, inventory management updated stock levels.</p>
<p>Events can triggers one or more processes to respond to them. For example: sending an email receipt, transmitting funds to an account, updating a real-time dashboard.</p>
<p>Event streaming is the process of capturing events in real-time from sources (such as web applications, databases, or sensors) to create streams of events. These streams are potentially unending sequences of records.</p>
<p>The event stream can be stored, processed, and sent to different destinations, also called sinks. The destinations that consume the streams could be other applications, databases, or data pipelines for further processing.</p>
<p>As applications have become more complex, often being broken up into different microservices distributed across multiple data centers, many organizations have adopted an event-driven architecture for their applications.</p>
<p>This means that instead of parts of your application directly asking each other for updates about what happened, they each publish events to event streams. Other parts of the application continuously subscribe to these streams and only act when they receive an event that they are interested in.</p>
<p>This architecture helps ensure that if part of your application goes down, other parts won't also fail. Additionally, you can add new features by adding new subscribers to the event stream, without having to rewrite the existing codebase.</p>
<h2 id="heading-core-kafka-concepts">Core Kafka Concepts</h2>
<p>Kafka has become one of the most popular ways to implement event streaming and event-driven architectures. But it does have a bit of a learning curve and you need to understand a couple of concepts before you can make effective use of it.</p>
<p>These core concepts are:</p>
<ul>
<li><p>event messages</p>
</li>
<li><p>topics</p>
</li>
<li><p>partitions</p>
</li>
<li><p>offsets</p>
</li>
<li><p>brokers</p>
</li>
<li><p>producers</p>
</li>
<li><p>consumers</p>
</li>
<li><p>consumer groups</p>
</li>
<li><p>Zookeeper</p>
</li>
</ul>
<h3 id="heading-event-messages-in-kafka">Event Messages in Kafka</h3>
<p>When you write data to Kafka, or read data from it, you do this in the form of messages. You'll also see them called events or records.</p>
<p>A message consists of:</p>
<ul>
<li><p>a key</p>
</li>
<li><p>a value</p>
</li>
<li><p>a timestamp</p>
</li>
<li><p>a compression type</p>
</li>
<li><p>headers for metadata (optional)</p>
</li>
<li><p>partition and offset id (once the message is written to a topic)</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/kafka-message-anatomy.PNG" alt="A Kafka message consisting of key, value, timestamp, compression type, and headers." width="600" height="400" loading="lazy"></p>
<p><em>A Kafka message consisting of key, value, timestamp, compression type, and headers</em></p>
<p>Every event in Kafka is, at its simplest, a key-value pair. These are serialized into binary, since Kafka itself handles arrays of bytes rather than complex language-specific objects.</p>
<p><strong>Keys</strong> are usually strings or integers and aren't unique for every message. Instead, they point to a particular entity in the system, such as a specific user, order, or device. Keys can be null, but when they are included they are used for dividing topics into partitions (more on partitions below).</p>
<p>The message <strong>value</strong> contains details about the event that happened. This could be as simple as a string or as complex as an object with many nested properties. Values can be null, but usually aren't.</p>
<p>By default, the <strong>timestamp</strong> records when the message was created. You can overwrite this if your event actually occurred earlier and you want to record that time instead.</p>
<p>Messages are usually small (less than 1 MB) and sent in a standard data format, such as JSON, Avro, or Protobuf. Even so, they can be compressed to save on data. The <strong>compression type</strong> can be set to <code>gzip</code>, <code>lz4</code>, <code>snappy</code>, <code>zstd</code>, or <code>none</code>.</p>
<p>Events can also optionally have <strong>headers</strong>, which are key-value pairs of strings containing metadata, such as where the event originated from or where you want it routed to.</p>
<p>Once a message is sent into a Kafka topic, it also receives a partition number and offset id (more about these later).</p>
<h3 id="heading-topics-in-kafka">Topics in Kafka</h3>
<p>Kafka stores messages in a <strong>topic</strong>, an ordered sequence of events, also called an event log.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/topic.PNG" alt="A Kafka topic containing messages, each with a unique offset." width="600" height="400" loading="lazy"></p>
<p><em>A Kafka topic containing messages, each with a unique offset</em></p>
<p>Different topics are identified by their names and will store different kinds of events. For example a social media application might have <code>posts</code>, <code>likes</code>, and <code>comments</code> topics to record every time a user creates a post, likes a post, or leaves a comment.</p>
<p>Multiple applications can write to and read from the same topic. An application might also read messages from one topic, filter or transform the data, and then write the result to another topic.</p>
<p>One important feature of topics is that they are append-only. When you write a message to a topic, it's added to the end of the log. Events in a topic are immutable. Once they're written to a topic, you can't change them.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/producer-to-topics-consumer-from-topics.PNG" alt="A Producer writing events to topics and a Consumer reading events from topics." width="600" height="400" loading="lazy"></p>
<p><em>A Producer writing events to topics and a Consumer reading events from topics</em></p>
<p>Unlike with messaging queues, reading an event from a topic doesn't delete it. Events can be read as often as needed, perhaps several times by multiple different applications.</p>
<p>Topics are also durable, holding onto messages for a specific period (by default 7 days) by saving them to physical storage on disk.</p>
<p>You can configure topics so that messages expire after a certain amount of time, or when a certain amount of storage is exceeded. You can even store messages indefinitely as long as you can pay for the storage costs.</p>
<h3 id="heading-partitions-in-kafka">Partitions in Kafka</h3>
<p>In order to help Kafka to scale, topics can be divided into <strong>partitions</strong>. This breaks up the event log into multiple logs, each of which lives on a separate node in the Kafka cluster. This means that the work of writing and storing messages can be spread across multiple machines.</p>
<p>When you create a topic, you specify the amount of partitions it has. The partitions are themselves numbered, starting at 0. When a new event is written to a topic, it's appended to one of the topic's partitions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/partitioned-topic.PNG" alt="A topic divided into three partitions." width="600" height="400" loading="lazy"></p>
<p><em>A topic divided into three partitions</em></p>
<p>If messages have no key, they will be evenly distributed among partitions in a round robin manner: partition 0, then partition 1, then partition 2, and so on. This way, all partitions get an even share of the data but there's no guarantee about the ordering of messages.</p>
<p>Messages that have the same key will always be sent to the same partition, and in the same order. The key is run through a hashing function which turns it into an integer. This output is then used to select a partition.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/messages-with-without-keys.PNG" alt="Messages without keys being sent across partitions while messages with the same keys are sent to the same partition" width="600" height="400" loading="lazy"></p>
<p><em>Messages without keys are sent across partitions, while messages with the same keys are sent to the same partition</em></p>
<p>Messages within each partition are guaranteed to be ordered. For example, all messages with the same <code>customer_id</code> as their key will be sent to the same partition in the order in which Kafka received them.</p>
<h3 id="heading-offsets-in-kafka">Offsets in Kafka</h3>
<p>Each message in a partition gets an id that is an incrementing integer, called an <strong>offset</strong>. Offsets start at 0 and are incremented every time Kafka writes a message to a partition. This means that each message in a given partition has a unique offset.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/offsets.PNG" alt="Three partitions with offsets. Offsets are unique within a partition but not between partitions" width="600" height="400" loading="lazy"></p>
<p><em>Offsets are unique within a partition but not between partitions</em></p>
<p>Offsets are not reused, even when older messages get deleted. They continue to increment, giving each new message in the partition a unique id.</p>
<p>When data is read from a partition, it is read in order from the lowest existing offset upwards. We'll see more about offsets when we cover Kafka consumers.</p>
<h3 id="heading-brokers-in-kafka">Brokers in Kafka</h3>
<p>A single "server" running Kafka is called a <strong>broker</strong>. In reality, this might be a Docker container running in a virtual machine. But it can be a helpful mental image to think of brokers as individual servers.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/cluster-with-three-brokers.PNG" alt="A Kafka cluster made up of three brokers" width="600" height="400" loading="lazy"></p>
<p><em>A Kafka cluster made up of three brokers</em></p>
<p>Multiple brokers working together make up a Kafka cluster. There might be a handful of brokers in a cluster, or more than 100. When a client application connects to one broker, Kafka automatically connects it to every broker in the cluster.</p>
<p>By running as a cluster, Kafka becomes more scalable and fault-tolerant. If one broker fails, the others will take over its work to ensure there is no downtime or data loss.</p>
<p>Each broker manages a set of partitions and handles requests to write data to or read data from these partitions. Partitions for a given topic will be spread evenly across the brokers in a cluster to help with load balancing. Brokers also manage replicating partitions to keep their data backed up.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/brokers-with-partitions.PNG" alt="Partitions spread across brokers" width="600" height="400" loading="lazy"></p>
<p><em>Partitions spread across brokers</em></p>
<h3 id="heading-replication-in-kafka">Replication in Kafka</h3>
<p>To protect against data loss if a broker fails, Kafka writes the same data to copies of a partition on multiple brokers. This is called <strong>replication</strong>.</p>
<p>The main copy of a partition is called the leader, while the replicas are called followers.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/brokers-replication.PNG" alt="The data from the leader partition is copied to follower partitions on different brokers" width="600" height="400" loading="lazy"></p>
<p><em>The data from the leader partition is copied to follower partitions on different brokers</em></p>
<p>When a topic is created, you set a replication factor for it. This controls how many replicas get written to. A replication factor of three is common, meaning data gets written to one leader and replicated to two followers. So even if two brokers failed, your data would still be safe.</p>
<p>Whenever you write messages to a partition, you're writing to the leader partition. Kafka then automatically copies these messages to the followers. As such, the logs on the followers will have the same messages and offsets as on the leader.</p>
<p>Followers that are up to date with the leader are called <strong>In-Sync Replicas</strong> (ISRs). Kafka considers a message to be committed once a minimum number of replicas have saved it to their logs. You can configure this to get higher throughput at the expense of less certainty that a message has been backed up.</p>
<h3 id="heading-producers-in-kafka">Producers in Kafka</h3>
<p>Producers are client applications that write events to Kafka topics. These apps aren't themselves part of Kafka – you write them.</p>
<p>Usually you will use a library to help manage writing events to Kafka. There is an official client library for Java as well as dozens of community-supported libraries for languages such as Scala, JavaScript, Go, Rust, Python, C#, and C++.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/producer-writing-to-topics.PNG" alt="A Producer application writing to multiple topics" width="600" height="400" loading="lazy"></p>
<p><em>A Producer application writing to multiple topics</em></p>
<p>Producers are totally decoupled from consumers, which read from Kafka. They don't know about each other and their speed doesn't affect each other. Producers aren't affected if consumers fail, and the same is true for consumers.</p>
<p>If you need to, you could write an application that writes certain events to Kafka and reads other events from Kafka, making it both a producer and a consumer.</p>
<p>Producers take a key-value pair, generate a Kafka message, and then serialize it into binary for transmission across the network. You can adjust the configuration of producers to batch messages together based on their size or some fixed time limit to optimize writing messages to the Kafka brokers.</p>
<p>It's the producer that decides which partition of a topic to send each message to. Again, messages without keys will be distributed evenly among partitions, while messages with keys are all sent to the same partition.</p>
<h3 id="heading-consumers-in-kafka">Consumers in Kafka</h3>
<p>Consumers are client applications that read messages from topics in a Kafka cluster. Like with producers, you write these applications yourself and can make use of client libraries to support the programming language your application is built with.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/consumer-reading-from-topics.PNG" alt="A Consumer reading messages from multiple topics." width="600" height="400" loading="lazy"></p>
<p><em>A Consumer reading messages from multiple topics</em></p>
<p>Consumers can read from one or more partitions within a topic, and from one or more topics. Messages are read in order within a partition, from the lowest available offset to the highest. But if a consumer reads data from several partitions in the same topic, the message order <strong>between</strong> these partitions is not guaranteed.</p>
<p>For example, a consumer might read messages from partition 0, then partition 2, then partition 1, then back to partition 0. The messages from partition 0 will be read in order, but there might be messages from the other partitions mixed among them.</p>
<p>It's important to remember that reading a message does not delete it. The message is still available to be read by any other consumer that needs to access it. It's normal for multiple consumers to read from the same topic if they each have uses for the data in it.</p>
<p>By default, when a consumer starts up it will read from the current offset in a partition. But consumers can also be configured to go back and read from the oldest existing offset.</p>
<p>Consumers deserialize messages, converting them from binary into a collection of key-value pairs that your application can then work with. The format of a message should not change during a topic's lifetime or your producers and consumers won't be able to serialize and deserialize it correctly.</p>
<p>One thing to be aware of is that consumers request messages from Kafka, it doesn't push messages to them. This protects consumers from becoming overwhelmed if Kafka is handling a high volume of messages. If you want to scale consumers, you can run multiple instances of a consumer together in a <strong>consumer group</strong>.</p>
<h3 id="heading-consumer-groups-in-kafka">Consumer Groups in Kafka</h3>
<p>An application that reads from Kafka can create multiple instances of the same consumer to split up the work of reading from different partitions in a topic. These consumers work together as a <strong>consumer group</strong>.</p>
<p>When you create a consumer, you can assign it a group id. All consumers in a group will have the same group id.</p>
<p>You can create consumer instances in a group up to the number of partitions in a topic. So if you have a topic with 5 partitions, you can create up to 5 instances of the same consumer in a consumer group. If you ever have more consumers in a group than partitions, the extra consumer will remain idle.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/consumer-group.PNG" alt="Consumers in a consumer group reading messages from a topic's partitions" width="600" height="400" loading="lazy"></p>
<p><em>Consumers in a consumer group reading messages from a topic's partitions</em></p>
<p>If you add another consumer instance to a consumer group, Kafka will automatically redistribute the partitions among the consumers in a process called <strong>rebalancing</strong>.</p>
<p>Each partition is only assigned to one consumer in a group, but a consumer can read from multiple partitions. Also, multiple different consumer groups (meaning different applications) can read from the same topic at the same time.</p>
<p>Kafka brokers use an internal topic called <code>__consumer_offsets</code> to keep track of which messages a specific consumer group has successfully processed.</p>
<p>As a consumer reads from a partition, it regularly saves the offset it has read up to and sends this data to the broker it is reading from. This is called the <strong>consumer offset</strong> and is handled automatically by most client libraries.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/consumer-committing-offsets.PNG" alt="A Consumer committing the offsets it has read up to." width="600" height="400" loading="lazy"></p>
<p><em>A Consumer committing the offsets it has read up to</em></p>
<p>If a consumer crashes, the consumer offset helps the remaining consumers to know where to start from when they take over reading from the partition.</p>
<p>The same thing happens if a new consumer is added to the group. The consumer group rebalances, the new consumer is assigned a partition, and it picks up reading from the consumer offset of that partition.</p>
<h3 id="heading-kafka-zookeeper">Kafka Zookeeper</h3>
<p>One other topic that we briefly need to cover here is how Kafka clusters are managed. Currently this is usually done using <a target="_blank" href="https://zookeeper.apache.org/">Zookeeper</a>, a service for managing and synchronizing distributed systems. Like Kafka, it's maintained by the Apache Foundation.</p>
<p>Kafka uses Zookeeper to manage the brokers in a cluster, and requires Zookeeper even if you're running a Kafka cluster with only one broker.</p>
<p>Recently, a proposal has been accepted to remove Zookeeper and have Kafka manage itself (<a target="_blank" href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-500%3A+Replace+ZooKeeper+with+a+Self-Managed+Metadata+Quorum">KIP-500</a>), but this is not yet widely used in production.</p>
<p>Zookeeper keeps track of things like:</p>
<ul>
<li><p>Which brokers are part of a Kafka cluster</p>
</li>
<li><p>Which broker is the leader for a given partition</p>
</li>
<li><p>How topics are configured, such as the number of partitions and the location of replicas</p>
</li>
<li><p>Consumer groups and their members</p>
</li>
<li><p>Access Control Lists – who is allowed to write to and read from each topic</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/zookeeper-ensemble-1.PNG" alt="A Zookeeper ensemble managing the brokers in a Kafka cluster." width="600" height="400" loading="lazy"></p>
<p><em>A Zookeeper ensemble managing the brokers in a Kafka cluster</em></p>
<p>Zookeeper itself runs as a cluster called an ensemble. This means that Zookeeper can keep working even if one node in the cluster fails. New data gets written to the ensemble's leader and replicated to the followers. Your Kafka brokers can read this data from any of the Zookeeper nodes in the ensemble.</p>
<p>Now that you understand the main concepts behind Kafka, let's get some hands-on practice working with Kafka.</p>
<p>You're going to install Kafka on your own computer, practice interacting with Kafka brokers from the command line, and then build a simple producer and consumer application with Java.</p>
<h2 id="heading-how-to-install-kafka-on-your-computer">How to Install Kafka on Your Computer</h2>
<p>At the time of writing this guide, the latest stable version of Kafka is 3.3.1. Check <a target="_blank" href="https://kafka.apache.org/downloads">kafka.apache.org/downloads</a> to see if there is a more recent stable version. If there is, you can replace "3.3.1" with the latest stable version in all of the following instructions.</p>
<h3 id="heading-install-kafka-on-macos">Install Kafka on macOS</h3>
<p>If you're using macOS, I recommend using Homebrew to install Kafka. It will make sure you have Java installed before it installs Kafka.</p>
<p>If you don't already have Homebrew installed, install it by following the instructions at <a target="_blank" href="https://brew.sh/">brew.sh</a>.</p>
<p>Next, run <code>brew install kafka</code> in a terminal. This will install Kafka's binaries at <code>usr/local/bin</code>.</p>
<p>Finally, run <code>kafka-topics --version</code> in a terminal and you should see <code>3.3.1</code>. If you do, you're all set.</p>
<p>To make it easier to work with Kafka, you can add Kafka to the <code>PATH</code> environment variable. Open your <code>~/.bashrc</code> (if using Bash) or <code>~/.zshrc</code> (if using Zsh) and add the following line, replacing <code>USERNAME</code> with your username:</p>
<pre><code class="lang-python">PATH=<span class="hljs-string">"$PATH:/Users/USERNAME/kafka_2.13-3.3.1/bin"</span>
</code></pre>
<p>You'll need to close your terminal for this change to take effect.</p>
<p>Now, if you run <code>echo $PATH</code> you should see that the Kafka <code>bin</code> directory has been added to your path.</p>
<h3 id="heading-install-kafka-on-windows-wsl2-and-linux">Install Kafka on Windows (WSL2) and Linux</h3>
<p>Kafka isn't natively supported on Windows, so you will need to use either WSL2 or Docker. I'm going to show you WSL2 since it's the same steps as Linux.</p>
<p>To set up WSL2 on Widows, follow <a target="_blank" href="https://learn.microsoft.com/en-us/windows/wsl/install">the instructions in the official docs</a>.</p>
<p>From here on, the instructions are the same for both WSL2 and Linux.</p>
<p>First, install Java 11 by running the following commands:</p>
<pre><code class="lang-python">wget -O- https://apt.corretto.aws/corretto.key | sudo apt-key add - 

sudo add-apt-repository <span class="hljs-string">'deb https://apt.corretto.aws stable main'</span>

sudo apt-get update; sudo apt-get install -y java<span class="hljs-number">-11</span>-amazon-corretto-jdk
</code></pre>
<p>Once this has finished, run <code>java -version</code> and you should see something like:</p>
<pre><code class="lang-python">openjdk version <span class="hljs-string">"11.0.17"</span> <span class="hljs-number">2022</span><span class="hljs-number">-10</span><span class="hljs-number">-18</span> LTS
OpenJDK Runtime Environment Corretto<span class="hljs-number">-11.0</span><span class="hljs-number">.17</span><span class="hljs-number">.8</span><span class="hljs-number">.1</span> (build <span class="hljs-number">11.0</span><span class="hljs-number">.17</span>+<span class="hljs-number">8</span>-LTS)
OpenJDK <span class="hljs-number">64</span>-Bit Server VM Corretto<span class="hljs-number">-11.0</span><span class="hljs-number">.17</span><span class="hljs-number">.8</span><span class="hljs-number">.1</span> (build <span class="hljs-number">11.0</span><span class="hljs-number">.17</span>+<span class="hljs-number">8</span>-LTS, mixed mode)
</code></pre>
<p>From your root directory, download Kafka with the following command:</p>
<pre><code class="lang-bash">wget https://archive.apache.org/dist/kafka/3.3.1/kafka_2.13-3.3.1.tgz
</code></pre>
<p>The <code>2.13</code> means it is using version <code>2.13</code> of Scala, while <code>3.3.1</code> refers to the Kafka version.</p>
<p>Extract the contents of the download with:</p>
<pre><code class="lang-bash">tar xzf kafka_2.13-3.3.1.tgz
</code></pre>
<p>If you run <code>ls</code>, you'll now see <code>kafka_2.13-3.3.1</code> in your root directory.</p>
<p>To make it easier to work with Kafka, you can add Kafka to the <code>PATH</code> environment variable. Open your <code>~/.bashrc</code> (if using Bash) or <code>~/.zshrc</code> (if using Zsh) and add the following line, replacing <code>USERNAME</code> with your username:</p>
<pre><code class="lang-python">PATH=<span class="hljs-string">"$PATH:home/USERNAME/kafka_2.13-3.3.1/bin"</span>
</code></pre>
<p>You'll need to close your terminal for this change to take effect.</p>
<p>Now, if you run <code>echo $PATH</code> you should see that the Kafka <code>bin</code> directory has been added to your path.</p>
<p>Run <code>kafka-topics.sh --version</code> in a terminal and you should see <code>3.3.1</code>. If you do, you're all set.</p>
<h2 id="heading-how-to-start-zookeeper-and-kafka">How to Start Zookeeper and Kafka</h2>
<p>Since Kafka uses Zookeeper to manage clusters, you need to start Zookeeper before you start Kafka.</p>
<h3 id="heading-how-to-start-kafka-on-macos">How to Start Kafka on macOS</h3>
<p>In one terminal window, start Zookeeper with:</p>
<pre><code class="lang-bash">/usr/<span class="hljs-built_in">local</span>/bin/zookeeper-server-start /usr/<span class="hljs-built_in">local</span>/etc/zookeeper/zoo.cfg
</code></pre>
<p>In another terminal window, start Kafka with:</p>
<pre><code class="lang-bash">/usr/<span class="hljs-built_in">local</span>/bin/kafka-server-start /usr/<span class="hljs-built_in">local</span>/etc/kafka/server.properties
</code></pre>
<p>While using Kafka, you need to keep both these terminal windows open. Closing them will shut down Kafka.</p>
<h3 id="heading-how-to-start-kafka-on-windows-wsl2-and-linux">How to Start Kafka on Windows (WSL2) and Linux</h3>
<p>In one terminal window, start Zookeeper with:</p>
<pre><code class="lang-bash">~/kafka_2.13-3.3.1/bin/zookeeper-server-start.sh ~/kafka_2.13-3.3.1/config/zookeeper.properties
</code></pre>
<p>In another terminal window, start Kafka with:</p>
<pre><code class="lang-bash">~/kafka_2.13-3.3.1/bin/kafka-server-start.sh ~/kafka_2.13-3.3.1/config/server.properties
</code></pre>
<p>While using Kafka, you need to keep both these terminal windows open. Closing them will shut down Kafka.</p>
<p>Now that you have Kafka installed and running on your machine, it's time to get some hands-on practice.</p>
<h2 id="heading-the-kafka-cli">The Kafka CLI</h2>
<p>When you install Kafka, it comes with a Command Line Interface (CLI) that lets you create and manage topics, as well as produce and consume events.</p>
<p>First, make sure Zookeeper and Kafka are running in two terminal windows.</p>
<p>In a third terminal window, run <code>kafka-topics.sh</code> (on WSL2 or Linux) or <code>kafka-topics</code> (on macOS) to make sure the CLI is working. You'll see a list of all the options you can pass to the CLI.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/kafka-topics-sh.PNG" alt="A terminal displaying kafka-topics options." width="600" height="400" loading="lazy"></p>
<p><em>kafka-topics options</em></p>
<p><strong>Note:</strong> When working with the Kafka CLI, the command will be <code>kafka-topics.sh</code> on WSL2 and Linux. It will be <code>kafka-topics.sh</code> on macOS if you directly installed the Kafka binaries and <code>kafka-topics</code> if you used Homebrew. So if you're using Homebrew, remove the <code>.sh</code> extension from the example commands in this section.</p>
<h3 id="heading-how-to-list-topics">How to List Topics</h3>
<p>To see the topics available on the Kafka broker on your local machine, use:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --list
</code></pre>
<p>This means "Connect to the Kafka broker running on localhost:9092 and list all topics there". <code>--bootstrap-server</code> refers to the Kafka broker you are trying to connect to and <code>localhost:9092</code> is the IP address it's running at. You won't see any output since you haven't created any topics yet.</p>
<h3 id="heading-how-to-create-a-topic">How to Create a Topic</h3>
<p>To create a topic (with the default replication factor and number of partitions), use the <code>--create</code> and <code>--topic</code> options and pass them a topic name:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my_first_topic
</code></pre>
<p>If you use an <code>_</code> or <code>.</code> in your topic name, you will see the following warning:</p>
<pre><code class="lang-python">WARNING: Due to limitations <span class="hljs-keyword">in</span> metric names, topics <span class="hljs-keyword">with</span> a period (<span class="hljs-string">'.'</span>) <span class="hljs-keyword">or</span> underscore (<span class="hljs-string">'_'</span>) could collide. To avoid issues it <span class="hljs-keyword">is</span> best to use either, but <span class="hljs-keyword">not</span> both.
</code></pre>
<p>Since Kafka could confuse <code>my.first.topic</code> with <code>my_first_topic</code>, it's best to only use either underscores or periods when naming topics.</p>
<h3 id="heading-how-to-describe-topics">How to Describe Topics</h3>
<p>To describe the topics on a broker, use the <code>--describe</code> option:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --describe
</code></pre>
<p>This will print the details of all the topics on this broker, including the number of partitions and their replication factor. By default, these will both be set to <code>1</code>.</p>
<p>If you add the <code>--topic</code> option and the name of a topic, it will describe only that topic:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic my_first_topic
</code></pre>
<h3 id="heading-how-to-partition-a-topic">How to Partition a Topic</h3>
<p>To create a topic with multiple partitions, use the <code>--partitions</code> option and pass it a number:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my_second_topic --partitions 3
</code></pre>
<h3 id="heading-how-to-set-a-replication-factor">How to Set a Replication Factor</h3>
<p>To create a topic with a replication factor higher than the default, use the <code>--replication-factor</code> option and pass it a number:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my_third_topic --partitions 3 --replication-factor 3
</code></pre>
<p>You should get the following error:</p>
<pre><code class="lang-bash">ERROR org.apache.kafka.common.errors.InvalidReplicationFactorException: Replication factor: 2 larger than available brokers: 1.
</code></pre>
<p>Since you're only running one Kafka broker on your machine, you can't set a replication factor higher than one. If you were running a cluster with multiple brokers, you could set a replication factor as high as the total number of brokers.</p>
<h3 id="heading-how-to-delete-a-topic">How to Delete a Topic</h3>
<p>To delete a topic, use the <code>--delete</code> option and specify a topic with the <code>--topic</code> option:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic my_first_topic
</code></pre>
<p>You won't get any output to say the topic was deleted but you can check using <code>--list</code> or <code>--describe</code>.</p>
<h3 id="heading-how-to-use-kafka-console-producer">How to Use <code>kafka-console-producer</code></h3>
<p>You can produce messages to a topic from the command line using <code>kafka-console-producer</code>.</p>
<p>Run <code>kafka-console-producer.sh</code> to see the options you can pass to it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/kafka-console-producer.PNG" alt="Terminal showing kafka-console-producer options." width="600" height="400" loading="lazy"></p>
<p><em>kafka-console-producer options</em></p>
<p>To create a producer connected to a specific topic, run:</p>
<pre><code class="lang-bash">kafka-console-producer.sh --bootstrap-server localhost:9092 --topic TOPIC_NAME
</code></pre>
<p>Let's produce messages to the <code>my_first_topic</code> topic.</p>
<pre><code class="lang-bash">kafka-console-producer.sh --bootstrap-server localhost:9092 --topic my_first_topic
</code></pre>
<p>Your prompt will change and you will be able to type text. Press <code>enter</code> to send that message. You can keep sending messages until you press <code>ctrl</code> + <code>c</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/kafka-console-producer-sample-messages.PNG" alt="Sending messages using kafka-console-producer" width="600" height="400" loading="lazy"></p>
<p><em>Sending messages using kafka-console-producer</em></p>
<p>If you produce messages to a topic that doesn't exist, you'll get a warning, but the topic will be created and the messages will still get sent. It's better to create a topic in advance, however, so you can specify partitions and replication.</p>
<p>By default, the messages sent from <code>kafka-console-producer</code> have their keys set to <code>null</code>, and so they will be evenly distributed to all partitions.</p>
<p>You can set a key by using the <code>--property</code> option to set <code>parse.key</code> to be true and providing a key separator, such as <code>:</code></p>
<p>For example, we can create a <code>books</code> topic and use the books' genre as a key.</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --topic books --create

kafka-console-producer.sh --bootstrap-server localhost:9092 --topic books --property parse.key=<span class="hljs-literal">true</span> --property key.separator=:
</code></pre>
<p>Now you can enter keys and values in the format <code>key:value</code>. Anything to the left of the key separator will be interpreted as a message key, anything to the right as a message value.</p>
<pre><code class="lang-python">science_fiction:All Systems Red
fantasy:Uprooted
horror:Mexican Gothic
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/producing-messages-with-keys.PNG" alt="Producing messages with keys and values." width="600" height="400" loading="lazy"></p>
<p><em>Producing messages with keys and values</em></p>
<p>Now that you've produced messages to a topic from the command line, it's time to consume those messages from the command line.</p>
<h3 id="heading-how-to-use-kafka-console-consumer">How to Use <code>kafka-console-consumer</code></h3>
<p>You can consumer messages from a topic from the command line using <code>kafka-console-consumer</code>.</p>
<p>Run <code>kafka-console-consumer.sh</code> to see the options you can pass to it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/kafka-console-consumer.PNG" alt="Terminal showing kafka-console-consumer options" width="600" height="400" loading="lazy"></p>
<p><em>kafka-console-consumer options</em></p>
<p>To create a consumer, run:</p>
<pre><code class="lang-bash">kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic TOPIC_NAME
</code></pre>
<p>When you start a consumer, by default it will read messages as they are written to the end of the topic. It won't read messages that were previously sent to the topic.</p>
<p>If you want to read the messages you already sent to a topic, use the <code>--from-beginning</code> option to read from the beginning of the topic:</p>
<pre><code class="lang-bash">kafka-console-consumer --bootstrap-server localhost:9092 --topic my_first_topic --from-beginning
</code></pre>
<p>The messages might appear "out of order". Remember, messages are ordered <strong>within</strong> a partition but ordering can't be guaranteed <strong>between</strong> partitions. If you don't set a key, they will be sent round robin between partitions and ordering isn't guaranteed.</p>
<p>You can display additional information about messages, such as their key and timestamp, by using the <code>--property</code> option and setting the <code>print</code> property to true.</p>
<p>Use the <code>--formatter</code> option to set the message formatter and the <code>--property</code> option to select which message properties to print.</p>
<pre><code class="lang-bash">kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my_first_topic --from-beginning --formatter kafka.tools.DefaultMessageFormatter --property print.timestamp=<span class="hljs-literal">true</span> --property print.key=<span class="hljs-literal">true</span> --property print.value=<span class="hljs-literal">true</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/consuming-messages-from-a-topic-1.PNG" alt="Consuming messages from a topic" width="600" height="400" loading="lazy"></p>
<p><em>Consuming messages from a topic</em></p>
<p>We get the messages' timestamp, key, and value. Since we didn't assign any keys when we sent these messages to <code>my_first_topic</code>, their <code>key</code> is <code>null</code>.</p>
<h3 id="heading-how-to-use-kafka-consumer-groups">How to Use <code>kafka-consumer-groups</code></h3>
<p>You can run consumers in a consumer group using the Kafka CLI. To view the documentation for this, run:</p>
<pre><code class="lang-bash">kafka-consumer-groups.sh
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/kafka-consumer-groups.PNG" alt="kafka-consumer-groups options" width="600" height="400" loading="lazy"></p>
<p><em>kafka-consumer-groups options</em></p>
<p>First, create a topic with three partitions. Each consumer in a group will consume from one partition. If there are more consumers than partitions, any extra consumers will be idle.</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --topic fantasy_novels --create --partitions 3
</code></pre>
<p>You add a consumer to a group when you create it using the <code>--group</code> option. If you run the same command multiple times with the same group name, each new consumer will be added to the group.</p>
<p>To create the first consumer in your consumer group, run:</p>
<pre><code class="lang-bash">kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic fantasy_novels --group fantasy_consumer_group
</code></pre>
<p>Next, open two new terminal windows and run the same command again to add a second and third consumer to the consumer group.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/three-consumers-in-group.PNG" alt="Three consumers running in a consumer group." width="600" height="400" loading="lazy"></p>
<p><em>Three consumers running in a consumer group</em></p>
<p>In a different terminal window, create a producer and send a few messages with keys to the topic.</p>
<p><strong>Note:</strong> Since Kafka 2.4, Kafka will send messages in batches to one "sticky" partition for better performance. In order to demonstrate messages being sent round robin between partitions (without sending a large volume of messages), we can set the partitioner to <code>RoundRobinPartitioner</code>.</p>
<pre><code class="lang-bash">kafka-console-producer.sh --bootstrap-server localhost:9092 --topic fantasy_novels --property parse.key=<span class="hljs-literal">true</span> --property key.separator=: --property partitioner.class=org.apache.kafka.clients.producer.RoundRobinPartitioner

tolkien:The Lord of the Rings
le_guin:A Wizard of Earthsea
leckie:The Raven Tower
de_bodard:The House of Shattered Wings
okorafor:Who Fears Death
liu:The Grace of Kings
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/messages-spread-across-consumer-group.PNG" alt="Messages spread between consumers in a consumer group" width="600" height="400" loading="lazy"></p>
<p><em>Messages spread between consumers in a consumer group</em></p>
<p>If you stop one of the consumers, the consumer group will rebalance and future messages will be sent to the remaining consumers.</p>
<p>Now that you have some experience working with Kafka from the command line, the next step is to build a small application that connects to Kafka.</p>
<h2 id="heading-how-to-build-a-kafka-client-app-with-java">How to Build a Kafka Client App with Java</h2>
<p>We're going to build a simple Java app that both produces messages to and consumes messages from Kafka. For this we'll use the official Kafka Java client.</p>
<p>If at any point you get stuck, the full code for this project is <a target="_blank" href="https://github.com/gerhynes/kafka-java-app">available on GitHub</a>.</p>
<h3 id="heading-preliminaries">Preliminaries</h3>
<p>First of all, make sure you have Java (at least JDK 11) and Kafka installed.</p>
<p>We're going to send messages about characters from <em>The Lord of the Rings</em>. So let's create a topic for these messages with three partitions.</p>
<p>From the command line, run:</p>
<pre><code class="lang-bash">kafka-topics.sh --bootstrap-server localhost:9092 --create --topic lotr_characters --partitions 3
</code></pre>
<h3 id="heading-how-to-set-up-the-project">How to Set Up the Project</h3>
<p>I recommend using IntelliJ for Java projects, so go ahead and install the Community Edition if you don't already have it. You can download it from <a target="_blank" href="https://www.jetbrains.com/idea/">jetbrains.com/idea</a></p>
<p>In Intellij, select <code>File</code>, <code>New</code>, and <code>Project</code>.</p>
<p>Give your project a name and select a location for it on your computer. Make sure you have selected Java as the language, Maven as the build system, and that the JDK is at least Java 11. Then click <code>Create</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/new-maven-project.PNG" alt="Setting up a Maven project in IntelliJ" width="600" height="400" loading="lazy"></p>
<p><em>Setting up a Maven project in IntelliJ</em></p>
<p><strong>Note:</strong> If you're on Windows, IntelliJ can't use a JDK installed on WSL. To install Java on the Windows side of things, go to <a target="_blank" href="https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html">docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list</a> and download the Windows installer. Follow the installation steps, open a command prompt, and run <code>java -version</code>. You should see something like:</p>
<pre><code class="lang-python">openjdk version <span class="hljs-string">"11.0.18"</span> <span class="hljs-number">2023</span><span class="hljs-number">-01</span><span class="hljs-number">-17</span> LTS
OpenJDK Runtime Environment Corretto<span class="hljs-number">-11.0</span><span class="hljs-number">.18</span><span class="hljs-number">.10</span><span class="hljs-number">.1</span> (build <span class="hljs-number">11.0</span><span class="hljs-number">.18</span>+<span class="hljs-number">10</span>-LTS)
OpenJDK <span class="hljs-number">64</span>-Bit Server VM Corretto<span class="hljs-number">-11.0</span><span class="hljs-number">.18</span><span class="hljs-number">.10</span><span class="hljs-number">.1</span> (build <span class="hljs-number">11.0</span><span class="hljs-number">.18</span>+<span class="hljs-number">10</span>-LTS, mixed mode)
</code></pre>
<p>Once your Maven project finishes setting up, run the <code>Main</code> class to see "Hello world!" and make sure everything worked.</p>
<h3 id="heading-how-to-install-the-dependencies">How to Install the Dependencies</h3>
<p>Next, we're going to install our dependencies. Open up <code>pom.xml</code> and inside the <code>&lt;project&gt;</code> element, create a <code>&lt;dependencies&gt;</code> element.</p>
<p>We're going to use the Java Kafka client for interacting with Kafka and SLF4J for logging, so add the following inside your <code>&lt;dependencies&gt;</code> element:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients --&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.kafka<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>kafka-clients<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.3.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>  
<span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.slf4j<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>slf4j-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.0.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>  
<span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple --&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.slf4j<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>slf4j-simple<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.0.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>The package names and version numbers might be red, meaning you haven't downloaded them yet. If this happens, click on <code>View</code>, <code>Tool Windows</code>, and <code>Maven</code> to open the Maven menu. Click on the <code>Reload All Maven Projects</code> icon and Maven will install these dependencies.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/reload-maven.png" alt="Reloading Maven dependencies in IntelliJ" width="600" height="400" loading="lazy"></p>
<p><em>Reloading Maven dependencies in IntelliJ</em></p>
<p>Create a <code>HelloKafka</code> class in the same directory as your <code>Main</code> class and give it the following contents:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> org.example;

<span class="hljs-keyword">import</span> org.slf4j.Logger;  
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;  

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloKafka</span> </span>{  
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger log = LoggerFactory.getLogger(HelloKafka.class);  

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{  
        log.info(<span class="hljs-string">"Hello Kafka"</span>);  
    }  
}
</code></pre>
<p>To make sure your dependencies are installed, run this class and you should see <code>[main] INFO org.example.HelloKafka - Hello Kafka</code> printed to the IntelliJ console.</p>
<h3 id="heading-how-to-create-a-kafka-producer">How to Create a Kafka Producer</h3>
<p>Next, we're going to create a <code>Producer</code> class. You can call this whatever you want as long as it doesn't clash with another class. So don't use <code>KafkaProducer</code> as you'll need that class in a minute.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> org.example;  

<span class="hljs-keyword">import</span> org.slf4j.Logger;  
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;  

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Producer</span> </span>{  
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger log = LoggerFactory.getLogger(KafkaProducer.class);  

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{  
        log.info(<span class="hljs-string">"This class will produce messages to Kafka"</span>);  
    }  
}
</code></pre>
<p>All of our Kafka-specific code is going to go inside this class's <code>main()</code> method.</p>
<p>The first thing we need to do is configure a few properties for the producer. Add the following inside the <code>main()</code> method:</p>
<pre><code class="lang-java">Properties properties = <span class="hljs-keyword">new</span> Properties(); 

properties.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, <span class="hljs-string">"localhost:9092"</span>);  
properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());  
properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
</code></pre>
<p><code>Properties</code> stores a set of properties as pairs of strings. The ones we're using are:</p>
<ul>
<li><p><code>ProducerConfig.BOOTSTRAP_SERVERS_CONFIG</code> which specifies the IP address to use to access the Kafka cluster</p>
</li>
<li><p><code>ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG</code> which specifies the serializer to use for message keys</p>
</li>
<li><p><code>ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG</code> which specifies the serializer to use for message values</p>
</li>
</ul>
<p>We're going to connect to our local Kafka cluster running on <code>localhost:9092</code>, and use the <code>StringSerializer</code> since both our keys and values will be strings.</p>
<p>Now we can create our producer and pass it the configuration properties.</p>
<pre><code class="lang-java">KafkaProducer&lt;String, String&gt; producer = <span class="hljs-keyword">new</span> KafkaProducer&lt;&gt;(properties);
</code></pre>
<p>To send a message, we need to create a <code>ProducerRecord</code> and pass it to our producer. <code>ProducerRecord</code> contains a topic name, and optionally a key, value, and partition number.</p>
<p>We're going to create the <code>ProducerRecord</code> with the topic to use, the message's key, and the message's value.</p>
<pre><code class="lang-java">ProducerRecord&lt;String, String&gt; producerRecord = <span class="hljs-keyword">new</span> ProducerRecord&lt;&gt;(<span class="hljs-string">"lotr_characters"</span>, <span class="hljs-string">"hobbits"</span>, <span class="hljs-string">"Bilbo"</span>);
</code></pre>
<p>We can now use the producer's <code>send()</code> method to send the message to Kafka.</p>
<pre><code class="lang-java">producer.send(producerRecord);
</code></pre>
<p>Finally, we need to call the <code>close()</code> method to stop the producer. This method handles any messages currently being processed by <code>send()</code> and then closes the producer.</p>
<pre><code class="lang-java">producer.close();
</code></pre>
<p>Now it's time to run our producer. <strong>Make sure you have Zookeeper and Kafka running.</strong> Then run the <code>main()</code> method of the <code>Producer</code> class.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/java-producer-single-message.PNG" alt="Sending a message from a producer in a Java Kafka client app." width="600" height="400" loading="lazy"></p>
<p><em>Sending a message from a producer in a Java Kafka client app</em></p>
<p><strong>Note:</strong> On Windows, your producer might not be able to connect to a Kafka broker running on WSL. To fix this, you're going to need to do the following:</p>
<ul>
<li><p>In a WSL terminal, navigate to Kafka's config folder: <code>cd ~/kafka_2.13-3.3.1/config/</code></p>
</li>
<li><p>Open <code>server.properties</code>, for example with Nano: <code>nano server.properties</code></p>
</li>
<li><p>Uncomment <code>#listeners=PLAINTEXT//:9092</code></p>
</li>
<li><p>Replace it with <code>listeners=PLAINTEXT//[::1]:9092</code></p>
</li>
<li><p>In your <code>Producer</code> class, replace <code>"localhost:9092"</code> with <code>"[::1]:9092"</code></p>
</li>
</ul>
<p><code>[::1]</code>, or <code>0:0:0:0:0:0:0:1</code>, refers to the loopback address (or localhost) in IPv6. This is equivalent to <code>127.0.0.1</code> in IPv4.</p>
<p>If you change <code>listeners</code>, when you try to access the Kafka broker from the command line you'll also have to use the new IP address, so use <code>--bootstrap-server ::1:9092</code> instead of <code>--bootstrap-server localhost:9092</code> and it should work.</p>
<p>We can now check that <code>Producer</code> worked by using <code>kafka-console-consumer</code> in another terminal window to read from the <code>lotr_characters</code> topic and see the message printed to the console.</p>
<pre><code class="lang-bash">kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic lotr_characters --from-beginning
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/consumer-reading-single-message.PNG" alt="kafka-console-consumer reading the message sent by the producer in our Java app" width="600" height="400" loading="lazy"></p>
<p><em>kafka-console-consumer reading the message sent by the producer in our Java app</em></p>
<h3 id="heading-how-to-send-multiple-messages-and-use-callbacks">How to Send Multiple Messages and Use Callbacks</h3>
<p>So far we're only sending one message. If we update <code>Producer</code> to send multiple messages, we'll be able to see how keys are used to divide messages between partitions. We can also take this opportunity to use a callback to view the sent message's metadata.</p>
<p>To do this, we're going to loop over a collection of characters to generate our messages.</p>
<p>So replace this:</p>
<pre><code class="lang-java">ProducerRecord&lt;String, String&gt; producerRecord = <span class="hljs-keyword">new</span> ProducerRecord&lt;&gt;(<span class="hljs-string">"lotr_characters"</span>, <span class="hljs-string">"hobbits"</span>, <span class="hljs-string">"Bilbo"</span>);  

producer.send(producerRecord);
</code></pre>
<p>with this:</p>
<pre><code class="lang-java">HashMap&lt;String, String&gt; characters = <span class="hljs-keyword">new</span> HashMap&lt;String, String&gt;();  
characters.put(<span class="hljs-string">"hobbits"</span>, <span class="hljs-string">"Frodo"</span>);  
characters.put(<span class="hljs-string">"hobbits"</span>, <span class="hljs-string">"Sam"</span>);  
characters.put(<span class="hljs-string">"elves"</span>, <span class="hljs-string">"Galadriel"</span>);  
characters.put(<span class="hljs-string">"elves"</span>, <span class="hljs-string">"Arwen"</span>);
characters.put(<span class="hljs-string">"humans"</span>, <span class="hljs-string">"Éowyn"</span>);  
characters.put(<span class="hljs-string">"humans"</span>, <span class="hljs-string">"Faramir"</span>);

<span class="hljs-keyword">for</span> (HashMap.Entry&lt;String, String&gt; character : characters.entrySet()) {  
    ProducerRecord&lt;String, String&gt; producerRecord = <span class="hljs-keyword">new</span> ProducerRecord&lt;&gt;(<span class="hljs-string">"lotr_characters"</span>, character.getKey(), character.getValue());  

    producer.send(producerRecord, (RecordMetadata recordMetadata, Exception err) -&gt; {  
        <span class="hljs-keyword">if</span> (err == <span class="hljs-keyword">null</span>) {  
            log.info(<span class="hljs-string">"Message received. \n"</span> +  
                    <span class="hljs-string">"topic ["</span> + recordMetadata.topic() + <span class="hljs-string">"]\n"</span> +  
                    <span class="hljs-string">"partition ["</span> + recordMetadata.partition() + <span class="hljs-string">"]\n"</span> +  
                    <span class="hljs-string">"offset ["</span> + recordMetadata.offset() + <span class="hljs-string">"]\n"</span> +  
                    <span class="hljs-string">"timestamp ["</span> + recordMetadata.timestamp() + <span class="hljs-string">"]"</span>);  
        } <span class="hljs-keyword">else</span> {  
            log.error(<span class="hljs-string">"An error occurred while producing messages"</span>, err);  
        }  
    });  
}
</code></pre>
<p>Here, we're iterating over the collection, creating a <code>ProducerRecord</code> for each entry, and passing the record to <code>send()</code>. Behind the scenes, Kafka will batch these messages together to make fewer network requests. <code>send()</code> can also take a callback as a second argument. We're going to pass it a lambda which will run code when the <code>send()</code> request completes.</p>
<p>If the request completed successfully, we get back a <code>RecordMetadata</code> object with metadata about the message, which we can use to see things such as the partition and offset the message ended up in.</p>
<p>If we get back an exception, we could handle it by retrying to send the message, or alerting our application. In this case, we're just going to log the exception.</p>
<p>Run the <code>main()</code> method of the <code>Producer</code> class and you should see the message metadata get logged.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/java-producer.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The full code for the <code>Producer</code> class should now be:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> org.example;  

<span class="hljs-keyword">import</span> org.apache.kafka.clients.producer.KafkaProducer;  
<span class="hljs-keyword">import</span> org.apache.kafka.clients.producer.ProducerConfig;  
<span class="hljs-keyword">import</span> org.apache.kafka.clients.producer.ProducerRecord;  
<span class="hljs-keyword">import</span> org.apache.kafka.clients.producer.RecordMetadata;  
<span class="hljs-keyword">import</span> org.apache.kafka.common.serialization.StringSerializer;  
<span class="hljs-keyword">import</span> org.slf4j.Logger;  
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;  

<span class="hljs-keyword">import</span> java.util.HashMap;  
<span class="hljs-keyword">import</span> java.util.Properties;  

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Producer</span> </span>{  
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger log = LoggerFactory.getLogger(Producer.class);  

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{  
        log.info(<span class="hljs-string">"This class produces messages to Kafka"</span>);  

        Properties properties = <span class="hljs-keyword">new</span> Properties();
        properties.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, <span class="hljs-string">"localhost:9092"</span>); 
        properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());  
        properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());  

        KafkaProducer&lt;String, String&gt; producer = <span class="hljs-keyword">new</span> KafkaProducer&lt;&gt;(properties);  

        HashMap&lt;String, String&gt; characters = <span class="hljs-keyword">new</span> HashMap&lt;String, String&gt;();  
        characters.put(<span class="hljs-string">"hobbits"</span>, <span class="hljs-string">"Frodo"</span>);  
        characters.put(<span class="hljs-string">"hobbits"</span>, <span class="hljs-string">"Sam"</span>);  
        characters.put(<span class="hljs-string">"elves"</span>, <span class="hljs-string">"Galadriel"</span>);  
        characters.put(<span class="hljs-string">"elves"</span>, <span class="hljs-string">"Arwen"</span>);
        characters.put(<span class="hljs-string">"humans"</span>, <span class="hljs-string">"Éowyn"</span>);  
        characters.put(<span class="hljs-string">"humans"</span>, <span class="hljs-string">"Faramir"</span>); 

        <span class="hljs-keyword">for</span> (HashMap.Entry&lt;String, String&gt; character : characters.entrySet()) {  
            ProducerRecord&lt;String, String&gt; producerRecord = <span class="hljs-keyword">new</span> ProducerRecord&lt;&gt;(<span class="hljs-string">"lotr_characters"</span>, character.getKey(), character.getValue());  

            producer.send(producerRecord, (RecordMetadata recordMetadata, Exception err) -&gt; {  
                <span class="hljs-keyword">if</span> (err == <span class="hljs-keyword">null</span>) {  
                    log.info(<span class="hljs-string">"Message received. \n"</span> +  
                            <span class="hljs-string">"topic ["</span> + recordMetadata.topic() + <span class="hljs-string">"]\n"</span> +  
                            <span class="hljs-string">"partition ["</span> + recordMetadata.partition() + <span class="hljs-string">"]\n"</span> +  
                            <span class="hljs-string">"offset ["</span> + recordMetadata.offset() + <span class="hljs-string">"]\n"</span> +  
                            <span class="hljs-string">"timestamp ["</span> + recordMetadata.timestamp() + <span class="hljs-string">"]"</span>);  
                } <span class="hljs-keyword">else</span> {  
                    log.error(<span class="hljs-string">"An error occurred while producing messages"</span>, err);  
                }  
            });  
        }
        producer.close();  
    }  
}
</code></pre>
<p>Next, we're going to create a consumer to read these messages from Kafka.</p>
<h3 id="heading-how-to-create-a-kafka-consumer">How to Create a Kafka Consumer</h3>
<p>First, create a <code>Consumer</code> class. Again, you can call it whatever you want, but don't call it <code>KafkaConsumer</code> as you will need that class in a moment.</p>
<p>All the Kafka-specific code will go in <code>Consumer</code>'s <code>main()</code> method.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> org.example;  

<span class="hljs-keyword">import</span> org.slf4j.Logger;  
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;  

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Consumer</span> </span>{  
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger log = LoggerFactory.getLogger(Consumer.class);  

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{  
        log.info(<span class="hljs-string">"This class consumes messages from Kafka"</span>);  
    }  
}
</code></pre>
<p>Next, configure the consumer properties.</p>
<pre><code class="lang-java">Properties properties = <span class="hljs-keyword">new</span> Properties();  
properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, <span class="hljs-string">"localhost:9092"</span>);  
properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());  
properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());  
properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, <span class="hljs-string">"lotr_consumer_group"</span>);  
properties.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, <span class="hljs-string">"earliest"</span>);
</code></pre>
<p>Just like with <code>Producer</code>, these properties are a set of string pairs. The ones we're using are:</p>
<ul>
<li><p><code>ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG</code> which specifies the IP address to use to access the Kafka cluster</p>
</li>
<li><p><code>ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG</code> which specifies the deserializer to use for message keys</p>
</li>
<li><p><code>ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG</code> which specifies the deserializer to use for message values</p>
</li>
<li><p><code>ConsumerConfig.GROUP_ID_CONFIG</code> which specifies the consumer group this consumer belongs to</p>
</li>
<li><p><code>ConsumerConfig.AUTO_OFFSET_RESET_CONFIG</code> which specifies the offset to start reading from</p>
</li>
</ul>
<p>We're connecting to the Kafka cluster on <code>localhost:9092</code>, using string deserializers since our keys and values are strings, setting a group id for our consumer, and telling the consumer to read from the start of the topic.</p>
<p><strong>Note:</strong> If you're running the consumer on Windows and accessing a Kafka broker running on WSL, you'll need to change <code>"localhost:9091"</code> to <code>"[::1]:9092"</code> or <code>"0:0:0:0:0:0:0:1:9092"</code>, like you did in <code>Producer</code>.</p>
<p>Next, we create a <code>KafkaConsumer</code> and pass it the configuration properties.</p>
<pre><code class="lang-java">KafkaConsumer&lt;String, String&gt; consumer = <span class="hljs-keyword">new</span> KafkaConsumer&lt;&gt;(properties);
</code></pre>
<p>We need to tell the consumer which topic, or topics, to subscribe to. The <code>subscribe()</code> method takes in a collection of one or more strings, naming the topics you want to read from. Remember, consumers can subscribe to more than one topic at the same time. For this example, we'll use one topic, the <code>lotr_characters</code> topic.</p>
<pre><code class="lang-java">String topic = <span class="hljs-string">"lotr_characters"</span>;  

consumer.subscribe(Arrays.asList(topic));
</code></pre>
<p>The consumer is now ready to start reading messages from the topic. It does this by regularly polling for new messages.</p>
<p>We'll use a while loop to repeatedly call the <code>poll()</code> method to check for new messages.</p>
<p><code>poll()</code> takes in a duration for how long it should read for at a time. It then batches these messages into an iterable called <code>ConsumerRecords</code>. We can then iterate over <code>ConsumerRecords</code> and do something with each individual <code>ConsumerRecord</code>.</p>
<p>In a real-world application, we would process this data or send it to some further destination, like a database or data pipeline. Here, we're just going to log the key, value, partition, and offset for each message we receive.</p>
<pre><code class="lang-java"><span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>){  
    ConsumerRecords&lt;String, String&gt; messages = consumer.poll(Duration.ofMillis(<span class="hljs-number">100</span>));  

    <span class="hljs-keyword">for</span> (ConsumerRecord&lt;String, String&gt; message : messages){  
        log.info(<span class="hljs-string">"key ["</span> + message.key() + <span class="hljs-string">"] value ["</span> + message.value() +<span class="hljs-string">"]"</span>);  
        log.info(<span class="hljs-string">"partition ["</span> + message.partition() + <span class="hljs-string">"] offset ["</span> + message.offset() + <span class="hljs-string">"]"</span>);  
    }  
}
</code></pre>
<p>Now it's time to run our consumer. <strong>Make sure you have Zookeeper and Kafka running.</strong> Run the <code>Consumer</code> class and you'll see the messages that <code>Producer</code> previously sent to the <code>lotr_characters</code> topic in Kafka.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/java-consumer-reading-from-topic.PNG" alt="The Kafka client app consuming messages that were previously produced to Kafka." width="600" height="400" loading="lazy"></p>
<p><em>The Kafka client app consuming messages that were previously produced to Kafka</em></p>
<h3 id="heading-how-to-shut-down-the-consumer">How to Shut Down the Consumer</h3>
<p>Right now, our consumer is running in an infinite loop and polling for new messages every 100 ms. This isn't a problem, but we should add safeguards to handle shutting down the consumer if an exception occurs.</p>
<p>We're going to wrap our code in a try-catch-finally block. If an exception occurs, we can handle it in the <code>catch</code> block.</p>
<p>The <code>finally</code> block will then call the consumer's <code>close()</code> method. This will close the socket the consumer is using, commit the offsets it has processed, and trigger a consumer group rebalance so any other consumers in the group can take over reading the partitions this consumer was handling.</p>
<pre><code class="lang-java"><span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// subscribe to topic(s)</span>
            String topic = <span class="hljs-string">"lotr_characters"</span>;
            consumer.subscribe(Arrays.asList(topic));

            <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {
                <span class="hljs-comment">// poll for new messages</span>
                ConsumerRecords&lt;String, String&gt; messages = consumer.poll(Duration.ofMillis(<span class="hljs-number">100</span>));

                <span class="hljs-comment">// handle message contents</span>
                <span class="hljs-keyword">for</span> (ConsumerRecord&lt;String, String&gt; message : messages) {
                    log.info(<span class="hljs-string">"key ["</span> + message.key() + <span class="hljs-string">"] value ["</span> + message.value() + <span class="hljs-string">"]"</span>);
                    log.info(<span class="hljs-string">"partition ["</span> + message.partition() + <span class="hljs-string">"] offset ["</span> + message.offset() + <span class="hljs-string">"]"</span>);
                }
            }
        } <span class="hljs-keyword">catch</span> (Exception err) {
            <span class="hljs-comment">// catch and handle exceptions</span>
            log.error(<span class="hljs-string">"Error: "</span>, err);
        } <span class="hljs-keyword">finally</span> {
            <span class="hljs-comment">// close consumer and commit offsets</span>
            consumer.close();
            log.info(<span class="hljs-string">"consumer is now closed"</span>);
        }
</code></pre>
<p><code>Consumer</code> will continuously poll its assigned topics for new messages and shut down safely if it experiences an exception.</p>
<p>The full code for the <code>Consumer</code> class should now be:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> org.example;

<span class="hljs-keyword">import</span> org.apache.kafka.clients.consumer.ConsumerConfig;
<span class="hljs-keyword">import</span> org.apache.kafka.clients.consumer.ConsumerRecord;
<span class="hljs-keyword">import</span> org.apache.kafka.clients.consumer.ConsumerRecords;
<span class="hljs-keyword">import</span> org.apache.kafka.clients.consumer.KafkaConsumer;
<span class="hljs-keyword">import</span> org.apache.kafka.common.serialization.StringDeserializer;
<span class="hljs-keyword">import</span> org.slf4j.Logger;
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;

<span class="hljs-keyword">import</span> java.time.Duration;
<span class="hljs-keyword">import</span> java.util.Arrays;
<span class="hljs-keyword">import</span> java.util.Properties;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Consumer</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger log = LoggerFactory.getLogger(Consumer.class);

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        log.info(<span class="hljs-string">"This class consumes messages from Kafka"</span>);

        Properties properties = <span class="hljs-keyword">new</span> Properties();
        properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, <span class="hljs-string">"localhost:9092"</span>);
        properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "lotr_consumer_group");
        properties.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

        KafkaConsumer&lt;String, String&gt; consumer = <span class="hljs-keyword">new</span> KafkaConsumer&lt;&gt;(properties);

        <span class="hljs-keyword">try</span> {
            String topic = <span class="hljs-string">"lotr_characters"</span>;
            consumer.subscribe(Arrays.asList(topic));

            <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {
                ConsumerRecords&lt;String, String&gt; messages = consumer.poll(Duration.ofMillis(<span class="hljs-number">100</span>));

                <span class="hljs-keyword">for</span> (ConsumerRecord&lt;String, String&gt; message : messages) {
                    log.info(<span class="hljs-string">"key ["</span> + message.key() + <span class="hljs-string">"] value ["</span> + message.value() + <span class="hljs-string">"]"</span>);
                    log.info(<span class="hljs-string">"partition ["</span> + message.partition() + <span class="hljs-string">"] offset ["</span> + message.offset() + <span class="hljs-string">"]"</span>);
                }
            }
        } <span class="hljs-keyword">catch</span> (Exception err) {
            log.error(<span class="hljs-string">"Error: "</span>, err);
        } <span class="hljs-keyword">finally</span> {
            consumer.close();
            log.info(<span class="hljs-string">"The consumer is now closed"</span>);
        }
    }
}
</code></pre>
<p>You now have a basic Java application that can send messages to and read messages from Kafka. If you got stuck at any point, <a target="_blank" href="https://github.com/gerhynes/kafka-java-app">the full code is available on GitHub</a>.</p>
<h2 id="heading-where-to-take-it-from-here">Where to Take it from Here</h2>
<p>Congratulations on making it this far. You've learned:</p>
<ul>
<li><p>the main concepts behind Kafka</p>
</li>
<li><p>how to communicate with Kafka from the command line</p>
</li>
<li><p>how to build a Java app that produces to and consumes from Kafka</p>
</li>
</ul>
<p>There's plenty more to learn about Kafka, whether that's <a target="_blank" href="https://kafka.apache.org/documentation/#connect">Kafka Connect</a> for connecting Kafka to common data systems or the <a target="_blank" href="https://kafka.apache.org/documentation/streams/">Kafka Streams API</a> for processing and transforming your data.</p>
<p>Some resources you might find useful as you continue your journey with Kafka are:</p>
<ul>
<li><p>the <a target="_blank" href="https://kafka.apache.org/documentation/">official Kafka docs</a></p>
</li>
<li><p><a target="_blank" href="https://developer.confluent.io/learn-kafka/">courses from Confluent</a></p>
</li>
<li><p><a target="_blank" href="https://www.conduktor.io/kafka">Conduktor's kafkademy</a></p>
</li>
</ul>
<p>I hope this guide has been helpful and made you excited to learn more about Kafka, event streaming, and real-time data processing.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Format Compact Numbers with the JavaScript Internationalization API ]]>
                </title>
                <description>
                    <![CDATA[ Sometimes it can be difficult to fit large numbers into your site or app's layout, especially if you have to display several of them together. As a result, a lot of modern sites and apps use the same format to display large numbers in a compact way. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/format-compact-numbers-with-javascript/</link>
                <guid isPermaLink="false">66d45edda3a4f04fb2dd2e49</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ internationalization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gerard Hynes ]]>
                </dc:creator>
                <pubDate>Wed, 04 Jan 2023 15:39:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/Format-Compact-Numbers.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Sometimes it can be difficult to fit large numbers into your site or app's layout, especially if you have to display several of them together.</p>
<p>As a result, a lot of modern sites and apps use the same format to display large numbers in a compact way. For example, displaying 123,000 as 123K.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/freecodecamp_socials.png" alt="freeCodeCamp's YouTube and Instagram profiles using compact number format." width="600" height="400" loading="lazy"></p>
<p><em>freeCodeCamp's YouTube and Instagram profiles using compact number format.</em></p>
<p>You can do this by writing a custom format function, using a third-party library, or, best of all, using a built-in JavaScript API.</p>
<p>You can of course write your own formatter function (and there are several available on Stack Overflow) but you will end up having to check for a lot of conditions.</p>
<p>As an aside, since ES2021, JavaScript supports using underscores as numeric separators to make large numbers easier to read in your code.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatCompactNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">if</span> (number &lt; <span class="hljs-number">1000</span>) {
    <span class="hljs-keyword">return</span> number;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1000</span> &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1000</span>).toFixed(<span class="hljs-number">1</span>) + <span class="hljs-string">"K"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000).toFixed(<span class="hljs-number">1</span>) + <span class="hljs-string">"M"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000_000).toFixed(<span class="hljs-number">1</span>) + <span class="hljs-string">"B"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000_000_000).toFixed(<span class="hljs-number">1</span>) + <span class="hljs-string">"T"</span>;
  }
}

formatCompactNumber(<span class="hljs-number">12</span>_000);        <span class="hljs-comment">// 12.0K</span>
formatCompactNumber(<span class="hljs-number">2</span>_000_000);     <span class="hljs-comment">// 2.0M</span>
formatCompactNumber(<span class="hljs-number">2</span>_500_000);     <span class="hljs-comment">// 2.5M</span>
formatCompactNumber(<span class="hljs-number">6</span>_000_000_000); <span class="hljs-comment">// 6.0B</span>
formatCompactNumber(<span class="hljs-number">6</span>_900_000_000); <span class="hljs-comment">// 6.9B</span>
</code></pre>
<p>This implementation still leaves a <code>.0</code> after an even thousand, million, billion, or trillion. You could fix this using the <code>replace</code> method and a regular expression.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatCompactNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">if</span> (number &lt; <span class="hljs-number">1000</span>) {
    <span class="hljs-keyword">return</span> number;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1000</span> &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1000</span>).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"K"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"M"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000_000).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"B"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000_000_000).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"T"</span>;
  }
}
</code></pre>
<p>But what if you need to handle negative numbers? You could add another conditional.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatCompactNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">if</span> (number &lt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"-"</span> + formatCompactNumber(<span class="hljs-number">-1</span> * number);
  }
  <span class="hljs-keyword">if</span> (number &lt; <span class="hljs-number">1000</span>) {
    <span class="hljs-keyword">return</span> number;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1000</span> &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1000</span>).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"K"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"M"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000_000).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"B"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number &gt;= <span class="hljs-number">1</span>_000_000_000_000 &amp;&amp; number &lt; <span class="hljs-number">1</span>_000_000_000_000_000) {
    <span class="hljs-keyword">return</span> (number / <span class="hljs-number">1</span>_000_000_000_000).toFixed(<span class="hljs-number">1</span>).replace(<span class="hljs-regexp">/\.0$/</span>, <span class="hljs-string">""</span>) + <span class="hljs-string">"T"</span>;
  }
}
</code></pre>
<p>As you can probably see by now, this only scratches the surface of things you would need to consider when writing your own function for displaying compact numbers.</p>
<p>There are a <a target="_blank" href="https://www.npmjs.com/search?q=compact%20number">handful of npm packages</a> for formatting numbers compactly. For example, you could install <a target="_blank" href="https://github.com/snewcomer/cldr-compact-number"><code>cldr-compact-number</code></a>, but this would also add 3 kilobytes (or 1.2 kilobytes gzipped) to your JavaScript bundle, adding slightly to your pageload time.</p>
<p>Thankfully, you don't need to use any third-party libraries to format compact numbers, since there is a relatively simple solution that is natively supported in JavaScript.</p>
<h2 id="heading-how-to-use-the-javascript-internationalization-api">How to Use the JavaScript Internationalization API</h2>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl">JavaScript Internationalization API</a> helps you to support different languages and formatting conventions when working in JavaScript. This could be anything from formatting dates and times to knowing whether <em>a</em> or <em>ä</em> comes first when comparing strings.</p>
<p>The API has excellent browser support, with <a target="_blank" href="https://caniuse.com/?search=Internationalization%20API">98% support worldwide</a>. It works by using the <code>Intl</code> object to create a namespace for language-sensitive string comparison, number formatting, and date and time formatting.</p>
<p>As well as <code>Intl.DateTimeFormat</code> for formatting dates and times, and <code>Intl.Collator</code> for doing language-sensitive string comparison, there is <code>Intl.NumberFormat</code>. This lets you format numbers in a language-specific manner.</p>
<p>To get started, create a formatter using the <code>Intl.NumberFormat</code> constructor. Optionally, you can pass it one or more locales and an <code>options</code> object.</p>
<pre><code class="lang-js"><span class="hljs-keyword">new</span> <span class="hljs-built_in">Intl</span>.NumberFormat(locales, options);
</code></pre>
<p>A locale is a parameter that defines the user's language, region, or other localization preference. In this case it's an <a target="_blank" href="https://en.wikipedia.org/wiki/IETF_language_tag">IETF language tag</a>, such as "en-US" for US English, "zh-CH" for Mandarin, or "uk" for Ukrainian.</p>
<p>In the browser, you can access the user's locale using <code>navigator.language</code>. If you don't provide a locale, the API will attempt to use the user's locale from their browser.</p>
<p>The <code>options</code> object can contain values to control things like how to format currency, whether to use <code>l</code> or <code>liters</code>, or whether to display <code>+</code> or <code>-</code> for positive or negative values.</p>
<p>Once you have created a formatter, you can call its <code>format</code> method and pass it the number you want to format. It will return the number formatted according to whatever configuration you provided.</p>
<p>For example, you could use the Internationalization API to format financial values according to different currencies:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> number = <span class="hljs-number">12345678.99</span>

<span class="hljs-keyword">const</span> germanCurrencyFormatter = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Intl</span>.NumberFormat(<span class="hljs-string">"de-DE"</span>, { <span class="hljs-attr">style</span>: <span class="hljs-string">"currency"</span>, <span class="hljs-attr">currency</span>: <span class="hljs-string">"EUR"</span> });

<span class="hljs-keyword">const</span> chineseCurrencyFormatter = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Intl</span>.NumberFormat(<span class="hljs-string">"zh-CH"</span>, { <span class="hljs-attr">style</span>: <span class="hljs-string">"currency"</span>, <span class="hljs-attr">currency</span>: <span class="hljs-string">"CNY"</span> });

germanCurrencyFormatter.format(number); <span class="hljs-comment">// 12.345.678,99 €</span>
chineseCurrencyFormatter.format(number); <span class="hljs-comment">// ¥12,345,678.99</span>
</code></pre>
<p>One of the options that is available is <code>notation</code>. This controls the formatting when displaying numbers. The possible values for <code>notation</code> are:</p>
<ul>
<li><p><code>"standard"</code> – plain number formatting according to the conventions of the locale (the default)</p>
</li>
<li><p><code>"scientific"</code> – returns the order of magnitude for a number</p>
</li>
<li><p><code>"engineering"</code> – returns the exponent of ten when the number is divisible by three</p>
</li>
<li><p><code>"compact"</code> – returns a string representing the exponent, such as K for thousands</p>
</li>
</ul>
<p>So, for example, if you format the number 123456789 with the locale set to "en", you will get:</p>
<ul>
<li><p>standard: 123,456,789</p>
</li>
<li><p>scientific: 1.235E8</p>
</li>
<li><p>engineering: 123.457E6</p>
</li>
<li><p>compact: 123M</p>
</li>
</ul>
<p>If you want a formatter to display large numbers in a compact manner, set the locale to your desired locale and set <code>notation</code> to <code>"compact"</code> .</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> formatter = <span class="hljs-built_in">Intl</span>.NumberFormat(<span class="hljs-string">"en"</span>, { <span class="hljs-attr">notation</span>: <span class="hljs-string">"compact"</span> });
</code></pre>
<p>This can be used to create a much shorter formatting function:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatCompactNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">const</span> formatter = <span class="hljs-built_in">Intl</span>.NumberFormat(<span class="hljs-string">"en"</span>, { <span class="hljs-attr">notation</span>: <span class="hljs-string">"compact"</span> });
  <span class="hljs-keyword">return</span> formatter.format(number);
}

formatCompactNumber(<span class="hljs-number">-57</span>);               <span class="hljs-comment">// -57</span>
formatCompactNumber(<span class="hljs-number">999</span>);               <span class="hljs-comment">// 999</span>
formatCompactNumber(<span class="hljs-number">8</span>_554);             <span class="hljs-comment">// 8.5K</span>
formatCompactNumber(<span class="hljs-number">150</span>_000);           <span class="hljs-comment">// 150K</span>
formatCompactNumber(<span class="hljs-number">3</span>_237_512);         <span class="hljs-comment">// 3.2M</span>
formatCompactNumber(<span class="hljs-number">9</span>_782_716_897);     <span class="hljs-comment">// 9.8B</span>
formatCompactNumber(<span class="hljs-number">7</span>_899_693_036_970); <span class="hljs-comment">// 7.9T</span>
</code></pre>
<p>Now your site or app can display even the largest numbers compactly, making your layout that little bit neater and tidier.</p>
<h3 id="heading-thanks-for-reading">Thanks for reading!</h3>
<p>I hope this quick guide helps you when you're working with large numbers in JavaScript and perhaps encourages you to explore the Internationalization API further.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn the Eleventy Static Site Generator by Building and Deploying a Portfolio Website ]]>
                </title>
                <description>
                    <![CDATA[ What is Eleventy? Eleventy (also called 11ty) is a simple yet powerful static site generator. It uses JavaScript to transform data and templates into HTML pages. It’s beginner-friendly, has fast build times, and generates fast sites by default. It al... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-eleventy/</link>
                <guid isPermaLink="false">66d45ee1787a2a3b05af43aa</guid>
                
                    <category>
                        <![CDATA[ eleventy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Static Site Generators ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gerard Hynes ]]>
                </dc:creator>
                <pubDate>Tue, 06 Sep 2022 16:26:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/learn-eleventy.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="heading-what-is-eleventy">What is Eleventy?</h2>
<p>Eleventy (also called 11ty) is a simple yet powerful static site generator. It uses JavaScript to transform data and templates into HTML pages.</p>
<p>It’s beginner-friendly, has fast build times, and generates fast sites by default. It also has a very active and friendly community.</p>
<p>Eleventy excels at content-driven sites and is used by <a target="_blank" href="https://web.dev/">Google</a>, <a target="_blank" href="https://www.netlify.com/">Netlify</a>, <a target="_blank" href="https://digitalhumanities.mit.edu/">MIT</a>, <a target="_blank" href="https://worldwideweb.cern.ch/">CERN</a>, <a target="_blank" href="https://www.a11yproject.com/">the A11y Project</a>, <a target="_blank" href="https://eslint.org/">ESLint,</a> and more.</p>
<p>Since pages are generated ahead of time, they can be served as fast as possible from a Content Delivery Network (CDN). Eleventy also generates no client-side JavaScript, which helps your site to load faster.</p>
<p>In this tutorial, we're going to build a simple developer portfolio site to demonstrate some of the main features of Eleventy.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-29-at-17-46-26-Eleventy-Portfolio.png" alt="Eleventy portfolio homepage" width="600" height="400" loading="lazy"></p>
<p><em>Eleventy portfolio homepage</em></p>
<p>We’ll learn about:</p>
<ol>
<li><p>Setting up and configuring an Eleventy project</p>
</li>
<li><p>Templating and layouts</p>
</li>
<li><p>Handling CSS and images</p>
</li>
<li><p>Working with collections and data files</p>
</li>
<li><p>Shortcodes and Eleventy plugins</p>
</li>
<li><p>Deploying the site to Netlify</p>
</li>
</ol>
<p>The portfolio site will have:</p>
<ul>
<li><p>A Homepage</p>
</li>
<li><p>An About page</p>
</li>
<li><p>A Contact page (with contact form)</p>
</li>
<li><p>A Projects page</p>
</li>
<li><p>A page for each project (with case study)</p>
</li>
</ul>
<p>Eleventy can pull in data from APIs, a Content Management System (CMS), or from local files. To keep things simple, we’ll store our project data in Markdown files.</p>
<p>The full code for the finished portfolio is <a target="_blank" href="https://github.com/gerhynes/eleventy-portfolio">available on GitHub</a>. If you get stuck at any stage, please check your code against the finished site.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisite-install-nodejs">Prerequisite - Install Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-initial-project-setup">Initial Project Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-the-project">How to Configure the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-a-template">How to Add a Template</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-templates-in-eleventy">How to Use Templates in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-layouts-in-eleventy">How to Use Layouts in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-the-css-and-images">How to Configure the CSS and Images</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-partials-in-eleventy">How to Use Partials in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-collections-in-eleventy">How to Use Collections in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-directory-data-files">How to Use Directory Data Files</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-collections-in-templates">How to Use Collections in Templates</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-shortcodes">How to Use Shortcodes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-the-eleventy-image-plugin">How to Use the Eleventy Image Plugin</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-a-build-contact-form-with-netlify-forms">How to Build a Contact Form with Netlify Forms</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-to-netlify">How to Deploy to Netlify</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-where-to-take-it-from-here">Where to Take it from Here</a></p>
</li>
</ol>
<h3 id="heading-prerequisite-install-nodejs">Prerequisite - Install Node.js</h3>
<p>If you don’t already have Node.js installed, go to <a target="_blank" href="https://nodejs.org/en/">nodejs.org</a> and follow the instructions for your operating system.</p>
<p>Open a terminal and use <code>node --version</code> to make sure it’s installed. As long as it’s version 12 or newer, you’re good to go.</p>
<h2 id="heading-initial-project-setup">Initial Project Setup</h2>
<p>First, create a directory for your portfolio. You can call it <code>eleventy-portfolio</code> or whatever you want.</p>
<p>Open this directory in a terminal and run <code>npm init -y</code> to create a <code>package.json</code> file with the default settings.</p>
<p>Next, install Eleventy using <code>npm install --save-dev @11ty/eleventy</code>.</p>
<p>In the root directory of the project, create a <code>.gitignore</code> file with the following contents so that Git doesn’t track any unwanted files:</p>
<pre><code class="lang-python">node_modules
/public
</code></pre>
<h2 id="heading-how-to-configure-the-project">How to Configure the Project</h2>
<p>Eleventy is “zero-config” by default. If you don’t change anything, Eleventy will take all the files in your root directory, run a build process, and output the resulting files to a <code>_site</code> directory.</p>
<p>But Eleventy also has flexible configuration options that let you customize your build process, watch for changes in certain file types, and manipulate content with filters and shortcodes.</p>
<p>Your Eleventy configuration goes in a <code>.eleventy.js</code> file in the root of your project.</p>
<p>For example, the default input directory is the root directory of your project, while the default output directory is <code>_site</code>. Some people prefer to change this, with <code>src</code> and <code>public</code> being common choices.</p>
<p>If you’d like this structure, create <code>src</code> and <code>public</code> directories in the root of your project and then set them as the input and output directories in <code>.eleventy.js</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">eleventyConfig</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">dir</span>: {
      <span class="hljs-attr">input</span>: <span class="hljs-string">"src"</span>,
      <span class="hljs-attr">output</span>: <span class="hljs-string">"public"</span>
    }
  };
};
</code></pre>
<p>In case you’re wondering, the <code>eleventyConfig</code> argument that is passed to the function is the default configuration object that Eleventy provides. Soon we’ll use this object to customize our Eleventy build process.</p>
<h2 id="heading-how-to-add-a-template">How to Add a Template</h2>
<p>Let’s add our first template. We’ll keep things as simple as possible by using a Markdown file.</p>
<p>In the <code>src</code> directory, create an <code>index.md</code> with <code># Hello World from Eleventy</code> as its contents. This is your first Eleventy template.</p>
<p>To build and view the site we can use the development server that comes with Eleventy.</p>
<p>In your terminal, make sure you’re in the root directory of your project and run <code>eleventy --serve</code>. This starts the development server, which will watch your <code>src</code> directory and automatically reload your site whenever you change your code.</p>
<p>After a moment you’ll see:</p>
<pre><code class="lang-python">[Browsersync] Access URLs:
 ----------------------------------
    Local: http://localhost:<span class="hljs-number">8080</span>
 External: http://your_ip_address:<span class="hljs-number">8080</span>
 ----------------------------------
[Browsersync] Serving files <span class="hljs-keyword">from</span>: public
</code></pre>
<p>Open a web browser and go to <a target="_blank" href="http://localhost:8080"><code>http://localhost:8080</code></a>. Congratulations, you’ve made a (very simple) Eleventy site! 🥳🎉</p>
<p>At this stage, your project will have the following structure:</p>
<pre><code class="lang-python">node_modules/
public/
src/
.eleventy.js
.gitignore
package.lock.json
package.json
</code></pre>
<p>Most sites need more than one page, so we’re going to need to learn more about <strong>templates</strong>.</p>
<p>Before we do that, we can customize our build commands if we want to. This step is entirely optional.</p>
<h3 id="heading-optional-step-how-to-create-custom-build-commands">Optional Step – How to Create Custom Build Commands</h3>
<p>The default command to run the development server is <code>eleventy --serve</code>, while the default command to build the site is <code>eleventy</code>.</p>
<p>If you’d like to replace these with different commands, such as <code>start</code> and <code>build</code>, open <code>package.json</code> and under <code>scripts</code> replace the “test” command with your preferred commands:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"eleventy --serve"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"eleventy"</span>
  },
</code></pre>
<p>Now we can use <code>npm start</code> in the terminal to start the development server and <code>npm run build</code> to generate a build of our site.</p>
<p>You can use <code>ctrl/cmd</code> + <code>c</code> to stop the development server whenever you need to.</p>
<h2 id="heading-how-to-use-templates-in-eleventy">How to Use Templates in Eleventy</h2>
<p>Turning Markdown files into HTML is neat, but so far you aren’t really getting much benefit over just writing your site in plain HTML. This is where <strong>templates</strong> come in.</p>
<p>First, we need to clarify some terms:</p>
<ul>
<li><p><strong>Template –</strong> A content file that Eleventy will transform into a page, or pages, in the built site</p>
</li>
<li><p><strong>Layout –</strong> A template that wraps around another template, usually to provide a structure to present content in</p>
</li>
<li><p><strong>Partial –</strong> A template that makes up part of another template</p>
</li>
</ul>
<p>Templates let you combine content and data to generate whatever HTML your site needs.</p>
<p>Layouts let you give multiple templates the same basic structure.</p>
<p>Partials let you build small reusable components that you can use in larger templates.</p>
<p>Eleventy supports ten different languages for templating, including: HTML, Markdown, JavaScript, Liquid, Nunjucks, Handlebars, Mustache, EJS, Haml, and Pug. (In version 1.0 Eleventy added support for custom templates using any arbitrary file extension, but this is probably better reserved for more custom/advanced use cases).</p>
<p>You can even mix different templating languages in the same file, such as Markdown and Nunjucks, if you want to.</p>
<p>In this project, we’ll use <a target="_blank" href="https://mozilla.github.io/nunjucks/">Nunjucks</a>. It’s a templating language for JavaScript created by Mozilla, and is pretty popular in the Eleventy community.</p>
<p>In the <code>src</code> directory, delete <code>index.md</code> and create an <code>index.njk</code> file. If you’re using VS Code, type <code>!</code> + <code>tab</code> to generate the basic HTML structure for the page. Change the title to "Eleventy Portfolio" and in the <code>&lt;body&gt;</code> element, add <code>&lt;h1&gt;Home Page&lt;/h1&gt;</code>.</p>
<p>Your page should look like this:</p>
<pre><code class="lang-python">&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;
&lt;head&gt;
  &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt;
  &lt;meta http-equiv=<span class="hljs-string">"X-UA-Compatible"</span> content=<span class="hljs-string">"IE=edge"</span>&gt;
  &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;
  &lt;title&gt;Eleventy Portfolio&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Home Page&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Next, still in <code>src</code>, create <code>about.njk</code> and <code>contact.njk</code> files. You can copy the contents of <code>index.njk</code> into them and replace the <code>&lt;h1&gt;</code> with <code>&lt;h1&gt;About Page&lt;/h1&gt;</code> and <code>&lt;h1&gt;Contact Page&lt;/h1&gt;</code> respectively.</p>
<p>Start your dev server. if it isn’t already running. Go to <a target="_blank" href="http://localhost:8080"><code>http://localhost:8080</code></a> to see the homepage, <code>http://localhost:8080/about</code> for the About page, and <code>http://localhost:8080/contact</code> for the Contact page.</p>
<p>In our portfolio site, each of these pages is going to have the same basic layout. So instead of writing the same code in each page template, we’re going to use Eleventy <strong>layouts</strong>.</p>
<h2 id="heading-how-to-use-layouts-in-eleventy">How to Use Layouts in Eleventy</h2>
<p>Layouts are templates that wrap around other templates, presenting the content in a consistent way.</p>
<p>Inside the <code>src</code> directory, create a <code>_includes</code> directory. This is going to contain all our layouts and partials.</p>
<p>Inside <code>_includes</code>, create a <code>base.njk</code> file. This will provide a standard layout for every page of our site.</p>
<p>Copy the following code into <code>base.njk</code>:</p>
<pre><code class="lang-python">&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;
&lt;head&gt;
  &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt;
  &lt;meta http-equiv=<span class="hljs-string">"X-UA-Compatible"</span> content=<span class="hljs-string">"IE=edge"</span>&gt;
  &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;
  &lt;meta name=<span class="hljs-string">"description"</span> content=<span class="hljs-string">"I'm a Frontend software developer who builds sites and apps that help people reach their personal and professional goals."</span>/&gt;
  &lt;title&gt;{{ title }}&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">content</span>"&gt;
    &lt;<span class="hljs-title">header</span> <span class="hljs-title">class</span>="<span class="hljs-title">header</span> <span class="hljs-title">container</span>"&gt;
    &lt;<span class="hljs-title">h1</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__title</span>"&gt;
      &lt;<span class="hljs-title">a</span> <span class="hljs-title">href</span>="/"&gt;<span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span>&lt;/<span class="hljs-title">a</span>&gt;
    &lt;/<span class="hljs-title">h1</span>&gt;
    &lt;<span class="hljs-title">ul</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__links</span>"&gt;
      &lt;<span class="hljs-title">li</span>&gt;
        &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">about</span>"&gt;<span class="hljs-title">About</span>&lt;/<span class="hljs-title">a</span>&gt;
      &lt;/<span class="hljs-title">li</span>&gt;
      &lt;<span class="hljs-title">li</span>&gt;
        &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">projects</span>"&gt;<span class="hljs-title">Projects</span>&lt;/<span class="hljs-title">a</span>&gt;
      &lt;/<span class="hljs-title">li</span>&gt;
      &lt;<span class="hljs-title">li</span>&gt;
        &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">contact</span>"&gt;<span class="hljs-title">Contact</span>&lt;/<span class="hljs-title">a</span>&gt;
      &lt;/<span class="hljs-title">li</span>&gt;
    &lt;/<span class="hljs-title">ul</span>&gt;
    &lt;/<span class="hljs-title">header</span>&gt;
    &lt;<span class="hljs-title">main</span> <span class="hljs-title">class</span>="<span class="hljs-title">main</span> <span class="hljs-title">container</span>"&gt;
      {{ <span class="hljs-title">content</span> | <span class="hljs-title">safe</span> }}
    &lt;/<span class="hljs-title">main</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">footer</span> <span class="hljs-title">class</span>="<span class="hljs-title">footer</span>"&gt;
      &lt;<span class="hljs-title">p</span>&gt;&amp;<span class="hljs-title">copy</span>; <span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span> 2022&lt;/<span class="hljs-title">p</span>&gt;
  &lt;/<span class="hljs-title">footer</span>&gt;
&lt;/<span class="hljs-title">body</span>&gt;
&lt;/<span class="hljs-title">html</span>&gt;</span>
</code></pre>
<p>The <code>content</code> value will be the main content of whichever template we use with <code>base.njk</code> as its layout. <code>safe</code> is a filter that prevents this content from being escaped (having potentially unsafe characters replaced).</p>
<p>Now, change <code>index.njk</code> to be:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;h1&gt;{{ title }} Home Page&lt;/h1&gt;
</code></pre>
<p>Notice how the template has frontmatter data at the top of the file. By default this is written in YAML, but you can use other languages too.</p>
<p>This frontmatter lets you set values for your templates. In this case, the <code>layout</code> value tells the template to use the <code>base.njk</code> layout and the <code>title</code> value provides a title that we are using in our template's <code>&lt;h1&gt;</code> tag.</p>
<p>Next, delete everything from <code>about.njk</code> and paste in the following content:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">bio</span> <span class="hljs-title">prose</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">heading</span>--<span class="hljs-title">main</span>"&gt;<span class="hljs-title">My</span> <span class="hljs-title">story</span>&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Lorem</span> <span class="hljs-title">ipsum</span> <span class="hljs-title">dolor</span> <span class="hljs-title">sit</span> <span class="hljs-title">amet</span>, <span class="hljs-title">consectetur</span> <span class="hljs-title">adipiscing</span> <span class="hljs-title">elit</span>, <span class="hljs-title">sed</span> <span class="hljs-title">do</span> <span class="hljs-title">eiusmod</span> <span class="hljs-title">tempor</span> <span class="hljs-title">incididunt</span> <span class="hljs-title">ut</span> <span class="hljs-title">labore</span> <span class="hljs-title">et</span> <span class="hljs-title">dolore</span> <span class="hljs-title">magna</span> <span class="hljs-title">aliqua</span>. <span class="hljs-title">Aliquet</span> <span class="hljs-title">risus</span> <span class="hljs-title">feugiat</span> <span class="hljs-title">in</span> <span class="hljs-title">ante</span> <span class="hljs-title">metus</span> <span class="hljs-title">dictum</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Tellus</span> <span class="hljs-title">pellentesque</span> <span class="hljs-title">eu</span> <span class="hljs-title">tincidunt</span> <span class="hljs-title">tortor</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">nulla</span> <span class="hljs-title">facilisi</span> <span class="hljs-title">cras</span> <span class="hljs-title">fermentum</span>. <span class="hljs-title">Turpis</span> <span class="hljs-title">egestas</span> <span class="hljs-title">integer</span> <span class="hljs-title">eget</span> <span class="hljs-title">aliquet</span>. <span class="hljs-title">Vestibulum</span> <span class="hljs-title">morbi</span> <span class="hljs-title">blandit</span> <span class="hljs-title">cursus</span> <span class="hljs-title">risus</span> <span class="hljs-title">at</span> <span class="hljs-title">ultrices</span> <span class="hljs-title">mi</span> <span class="hljs-title">tempus</span>. <span class="hljs-title">Ut</span> <span class="hljs-title">lectus</span> <span class="hljs-title">arcu</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">at</span>. <span class="hljs-title">Integer</span> <span class="hljs-title">enim</span> <span class="hljs-title">neque</span> <span class="hljs-title">volutpat</span> <span class="hljs-title">ac</span> <span class="hljs-title">tincidunt</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Commodo</span> <span class="hljs-title">ullamcorper</span> <span class="hljs-title">a</span> <span class="hljs-title">lacus</span> <span class="hljs-title">vestibulum</span> <span class="hljs-title">sed</span> <span class="hljs-title">arcu</span>. <span class="hljs-title">Et</span> <span class="hljs-title">tortor</span> <span class="hljs-title">consequat</span> <span class="hljs-title">id</span> <span class="hljs-title">porta</span> <span class="hljs-title">nibh</span> <span class="hljs-title">venenatis</span> <span class="hljs-title">cras</span> <span class="hljs-title">sed</span>. <span class="hljs-title">Nulla</span> <span class="hljs-title">pharetra</span> <span class="hljs-title">diam</span> <span class="hljs-title">sit</span> <span class="hljs-title">amet</span> <span class="hljs-title">nisl</span>. <span class="hljs-title">Ipsum</span> <span class="hljs-title">nunc</span> <span class="hljs-title">aliquet</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">enim</span> <span class="hljs-title">facilisis</span> <span class="hljs-title">gravida</span> <span class="hljs-title">neque</span> <span class="hljs-title">convallis</span> <span class="hljs-title">a</span>. <span class="hljs-title">Nec</span> <span class="hljs-title">sagittis</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">malesuada</span> <span class="hljs-title">bibendum</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Tellus</span> <span class="hljs-title">pellentesque</span> <span class="hljs-title">eu</span> <span class="hljs-title">tincidunt</span> <span class="hljs-title">tortor</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">nulla</span> <span class="hljs-title">facilisi</span> <span class="hljs-title">cras</span> <span class="hljs-title">fermentum</span>. <span class="hljs-title">Turpis</span> <span class="hljs-title">egestas</span> <span class="hljs-title">integer</span> <span class="hljs-title">eget</span> <span class="hljs-title">aliquet</span>. <span class="hljs-title">Vestibulum</span> <span class="hljs-title">morbi</span> <span class="hljs-title">blandit</span> <span class="hljs-title">cursus</span> <span class="hljs-title">risus</span> <span class="hljs-title">at</span> <span class="hljs-title">ultrices</span> <span class="hljs-title">mi</span> <span class="hljs-title">tempus</span>. <span class="hljs-title">Ut</span> <span class="hljs-title">lectus</span> <span class="hljs-title">arcu</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">at</span>. <span class="hljs-title">Integer</span> <span class="hljs-title">enim</span> <span class="hljs-title">neque</span> <span class="hljs-title">volutpat</span> <span class="hljs-title">ac</span> <span class="hljs-title">tincidunt</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Commodo</span> <span class="hljs-title">ullamcorper</span> <span class="hljs-title">a</span> <span class="hljs-title">lacus</span> <span class="hljs-title">vestibulum</span> <span class="hljs-title">sed</span> <span class="hljs-title">arcu</span>. <span class="hljs-title">Et</span> <span class="hljs-title">tortor</span> <span class="hljs-title">consequat</span> <span class="hljs-title">id</span> <span class="hljs-title">porta</span> <span class="hljs-title">nibh</span> <span class="hljs-title">venenatis</span> <span class="hljs-title">cras</span> <span class="hljs-title">sed</span>. <span class="hljs-title">Nulla</span> <span class="hljs-title">pharetra</span> <span class="hljs-title">diam</span> <span class="hljs-title">sit</span> <span class="hljs-title">amet</span> <span class="hljs-title">nisl</span>. <span class="hljs-title">Ipsum</span> <span class="hljs-title">nunc</span> <span class="hljs-title">aliquet</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">enim</span> <span class="hljs-title">facilisis</span> <span class="hljs-title">gravida</span> <span class="hljs-title">neque</span> <span class="hljs-title">convallis</span> <span class="hljs-title">a</span>. <span class="hljs-title">Nec</span> <span class="hljs-title">sagittis</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">malesuada</span> <span class="hljs-title">bibendum</span>.&lt;/<span class="hljs-title">p</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>Now delete everything from <code>contact.njk</code> and paste in this content:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;h2 <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">heading</span>--<span class="hljs-title">main</span> <span class="hljs-title">text</span>-<span class="hljs-title">center</span>"&gt;<span class="hljs-title">Want</span> <span class="hljs-title">to</span> <span class="hljs-title">get</span> <span class="hljs-title">in</span> <span class="hljs-title">touch</span>?&lt;/<span class="hljs-title">h2</span>&gt;
&lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">contact__sub</span>-<span class="hljs-title">heading</span> <span class="hljs-title">text</span>-<span class="hljs-title">center</span>"&gt;<span class="hljs-title">I</span>'<span class="hljs-title">m</span> <span class="hljs-title">always</span> <span class="hljs-title">open</span> <span class="hljs-title">to</span> <span class="hljs-title">new</span> <span class="hljs-title">opportunities</span> <span class="hljs-title">and</span> <span class="hljs-title">projects</span>. &lt;/<span class="hljs-title">p</span>&gt;

&lt;<span class="hljs-title">form</span> <span class="hljs-title">class</span>="<span class="hljs-title">form</span>" <span class="hljs-title">name</span>="<span class="hljs-title">contact</span>" <span class="hljs-title">action</span>="/<span class="hljs-title">success</span>" <span class="hljs-title">method</span>="<span class="hljs-title">POST</span>" <span class="hljs-title">data</span>-<span class="hljs-title">netlify</span>="<span class="hljs-title">true</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourName</span>"&gt;<span class="hljs-title">Name</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">name</span>" <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">id</span>="<span class="hljs-title">yourName</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourEmail</span>"&gt;<span class="hljs-title">Email</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">email</span>" <span class="hljs-title">type</span>="<span class="hljs-title">email</span>"  <span class="hljs-title">id</span>="<span class="hljs-title">yourEmail</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">message</span>"&gt;<span class="hljs-title">Message</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">textarea</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">message</span>" <span class="hljs-title">id</span>="<span class="hljs-title">message</span>" <span class="hljs-title">rows</span>="4" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;&lt;/<span class="hljs-title">textarea</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
    &lt;<span class="hljs-title">button</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__button</span>" <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>"&gt;<span class="hljs-title">Let</span>'<span class="hljs-title">s</span> <span class="hljs-title">talk</span>&lt;/<span class="hljs-title">button</span>&gt;
&lt;/<span class="hljs-title">form</span>&gt;</span>
</code></pre>
<p>We’re going to learn about how this contact form will work later in the tutorial.</p>
<p>Our portfolio is starting to take shape, even though things still look really bare. Let's get our CSS and images working next.</p>
<h2 id="heading-how-to-configure-the-css-and-images">How to Configure the CSS and Images</h2>
<p>While Eleventy can understand supported templating languages out of the box, it needs to be configured to process CSS and image files. Fortunately, this doesn’t require much configuration. While we’re at it, we’re also going to add a favicon to the site.</p>
<p>Inside the <code>src</code> directory, create three folders: <code>css</code>, <code>images</code>, and <code>favicons</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/src.PNG" alt="src directory structure" width="600" height="400" loading="lazy"></p>
<p><em>src directory structure</em></p>
<p>Inside the <code>css</code> directory, make a <code>style.css</code> file. Since this isn’t a CSS tutorial, I’m going to provide the CSS in <a target="_blank" href="https://github.com/gerhynes/eleventy-portfolio/tree/main/src">the GitHub repo for the project</a>. You can copy and paste it from there, but I’m not going to cover the CSS in any depth.</p>
<p>The images for this portfolio are also available in the <code>images</code> directory in the GitHub repo. Copy these images into the <code>images</code> directory of your project.</p>
<p>Finally, copy the files from the <code>favicons</code> directory in the GitHub repo into the <code>favicons</code> directory of your project.</p>
<p>In <code>base.njk</code> add these lines to the <code>&lt;head&gt;</code> element:</p>
<pre><code class="lang-python">&lt;link rel=<span class="hljs-string">"icon"</span> href=<span class="hljs-string">"/favicon.ico"</span> sizes=<span class="hljs-string">"any"</span>&gt;
&lt;link rel=<span class="hljs-string">"apple-touch-icon"</span> href=<span class="hljs-string">"/apple-touch-icon.png"</span>&gt;
&lt;link rel=<span class="hljs-string">"preconnect"</span> href=<span class="hljs-string">"https://fonts.googleapis.com"</span>&gt;
&lt;link rel=<span class="hljs-string">"preconnect"</span> href=<span class="hljs-string">"https://fonts.gstatic.com"</span> crossorigin&gt;
&lt;link href=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&amp;display=swap"</span> rel=<span class="hljs-string">"stylesheet"</span>&gt;
&lt;link rel=<span class="hljs-string">"stylesheet"</span> href=<span class="hljs-string">"{{'/css/style.css' | url | safe}}"</span>&gt;
</code></pre>
<p>The first two links include the favicon, the next three will fetch the Inter font from Google fonts, and the last one will connect <code>style.css</code> to <code>base.njk</code>.</p>
<p>Now, if we reload our homepage we’ll see that… absolutely nothing has changed.</p>
<p>By default, Eleventy will only process template files. To tell it to include CSS files and images, we need to add a few lines of configuration.</p>
<p>Add these lines to the configuration function in <code>.eleventy.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">eleventyConfig</span>) </span>{
  eleventyConfig.addPassthroughCopy(<span class="hljs-string">"./src/css/"</span>);
  eleventyConfig.addWatchTarget(<span class="hljs-string">"./src/css/"</span>);
  eleventyConfig.addPassthroughCopy(<span class="hljs-string">"./src/images/"</span>);
  eleventyConfig.addPassthroughCopy({ <span class="hljs-string">"./src/favicons"</span>: <span class="hljs-string">"/"</span> });

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">dir</span>: {
      <span class="hljs-attr">input</span>: <span class="hljs-string">"src"</span>,
      <span class="hljs-attr">output</span>: <span class="hljs-string">"public"</span>
    }
  };
};
</code></pre>
<p><code>addPassthroughCopy</code> tells Eleventy to pass the CSS, favicons, and image files through to the final build.</p>
<p><code>addWatchTarget</code> tells the Eleventy dev server to watch the <code>css</code> directory and reload the site if the files in this directory change.</p>
<p>With the favicons, we’re also telling Eleventy to output these files to the root of the generated content so that the links in <code>base.njk</code> will work.</p>
<p>Restart the server and you’ll see that the CSS is finally being applied and the favicon is showing up. We'll include the images shortly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-17-19-57-Eleventy-Portfolio.png" alt="Homepage with styles applied" width="600" height="400" loading="lazy"></p>
<p><em>Homepage with styles applied</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-16-28-Eleventy-Portfolio.png" alt="About page with styles applied." width="600" height="400" loading="lazy"></p>
<p><em>About page with styles applied</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-17-08-Eleventy-Portfolio.png" alt="Contact page with styles applied." width="600" height="400" loading="lazy"></p>
<p><em>Contact page with styles applied</em></p>
<p>The About page and Contact page are fairly self-contained. But the homepage for our site is going to have a couple of parts to it. It will consist of a header and footer, as well as a profile section, technologies section, and projects section. Each of these parts is going to use a <strong>partial</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/layout.png" alt="Layout of portfolio homepage." width="600" height="400" loading="lazy"></p>
<p><em>Layout of portfolio homepage</em></p>
<h2 id="heading-how-to-use-partials-in-eleventy">How to Use Partials in Eleventy</h2>
<p>Partials are templates that make up part of another template. Partials help us to think about our site in terms of reusable components that we can include whenever we need them.</p>
<p>In the <code>_includes</code> directory, create a <code>header.njk</code> and <code>footer.njk</code> file.</p>
<p>Cut the header element out of <code>base.njk</code> and paste it into <code>header.njk</code>.</p>
<p>Cut the footer element out of <code>base.njk</code> and paste it into <code>footer.njk</code>.</p>
<p>Back in <code>base.njk</code> add <code>{% include "header.njk" %}</code> where the header element used to be and <code>{% include "footer.njk" %}</code> where the footer element used to be.</p>
<p><code>base.njk</code> should now have this content inside its <code>&lt;body&gt;</code> tag:</p>
<pre><code class="lang-python">&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">content</span>"&gt;
    {% <span class="hljs-title">include</span> "<span class="hljs-title">header</span>.<span class="hljs-title">njk</span>" %}
    &lt;<span class="hljs-title">main</span> <span class="hljs-title">class</span>="<span class="hljs-title">main</span> <span class="hljs-title">container</span>"&gt;
      {{ <span class="hljs-title">content</span> | <span class="hljs-title">safe</span> }}
    &lt;/<span class="hljs-title">main</span>&gt;
&lt;/<span class="hljs-title">div</span>&gt;
{% <span class="hljs-title">include</span> "<span class="hljs-title">footer</span>.<span class="hljs-title">njk</span>" %}</span>
</code></pre>
<p>The site won’t look any different but our base layout is already becoming more modular.</p>
<p>Next, still in the <code>_includes</code> directory, create a <code>profile.njk</code> file with the following content:</p>
<pre><code class="lang-python">&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">profile</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__image</span>-<span class="hljs-title">wrapper</span>"&gt;
    &lt;<span class="hljs-title">img</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__image</span>" <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">profile</span>.<span class="hljs-title">jpg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span>, <span class="hljs-title">Software</span> <span class="hljs-title">Developer</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__card</span>"&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">Hi</span>! <span class="hljs-title">I</span>'<span class="hljs-title">m</span> &lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>--<span class="hljs-title">highlight</span>"&gt;<span class="hljs-title">Marie</span>&lt;/<span class="hljs-title">span</span>&gt;, <span class="hljs-title">a</span> <span class="hljs-title">mathematician</span> <span class="hljs-title">turned</span> <span class="hljs-title">software</span> <span class="hljs-title">developer</span> <span class="hljs-title">from</span> <span class="hljs-title">Hampton</span>, <span class="hljs-title">Virginia</span>.&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">As</span> <span class="hljs-title">a</span> &lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>--<span class="hljs-title">highlight</span>"&gt;<span class="hljs-title">Frontend</span> <span class="hljs-title">Developer</span>&lt;/<span class="hljs-title">span</span>&gt;, <span class="hljs-title">I</span> <span class="hljs-title">love</span> <span class="hljs-title">building</span> <span class="hljs-title">sites</span> <span class="hljs-title">and</span> <span class="hljs-title">apps</span> <span class="hljs-title">that</span> <span class="hljs-title">help</span> <span class="hljs-title">people</span> <span class="hljs-title">reach</span> <span class="hljs-title">their</span> <span class="hljs-title">personal</span> <span class="hljs-title">and</span> <span class="hljs-title">professional</span> <span class="hljs-title">goals</span>.&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">I</span> <span class="hljs-title">focus</span> <span class="hljs-title">on</span> <span class="hljs-title">speed</span>, <span class="hljs-title">security</span> <span class="hljs-title">and</span> <span class="hljs-title">scalability</span>, <span class="hljs-title">using</span> <span class="hljs-title">React</span>.<span class="hljs-title">js</span> <span class="hljs-title">and</span> <span class="hljs-title">Firebase</span> <span class="hljs-title">to</span> <span class="hljs-title">create</span> <span class="hljs-title">rich</span>, <span class="hljs-title">dynamic</span> <span class="hljs-title">experiences</span>.&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">I</span>'<span class="hljs-title">m</span> <span class="hljs-title">always</span> <span class="hljs-title">open</span> <span class="hljs-title">to</span> <span class="hljs-title">new</span> <span class="hljs-title">opportunities</span> <span class="hljs-title">and</span> <span class="hljs-title">projects</span>. <span class="hljs-title">So</span> <span class="hljs-title">don</span>'<span class="hljs-title">t</span> <span class="hljs-title">hesitate</span> <span class="hljs-title">to</span> &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">contact</span>"&gt;<span class="hljs-title">get</span> <span class="hljs-title">in</span> <span class="hljs-title">touch</span>&lt;/<span class="hljs-title">a</span>&gt;.&lt;<span class="hljs-title">p</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>Next, create a <code>technologies.njk</code> file with this content:</p>
<pre><code class="lang-python">&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">technologies</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__heading</span>"&gt;<span class="hljs-title">Technologies</span> <span class="hljs-title">I</span> <span class="hljs-title">love</span> <span class="hljs-title">to</span> <span class="hljs-title">work</span> <span class="hljs-title">with</span>&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">ul</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__list</span>"&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
      &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">javascript</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">JavaScript</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">JavaScript</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
      &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">react</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">React</span>.<span class="hljs-title">js</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">React</span>.<span class="hljs-title">js</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
        &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">tailwindcss</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Tailwind</span> <span class="hljs-title">CSS</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">Tailwind</span> <span class="hljs-title">CSS</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
        &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">firebase</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Firebase</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">Firebase</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
  &lt;/<span class="hljs-title">ul</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>In <code>index.njk</code> replace the <code>&lt;h1&gt;</code> tag with:</p>
<pre><code class="lang-python">{% include <span class="hljs-string">"profile.njk"</span> %}
{% include <span class="hljs-string">"technologies.njk"</span> %}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-15-11-Eleventy-Portfolio.png" alt="Portfolio homepage with profile and technologies sections." width="600" height="400" loading="lazy"></p>
<p><em>Portfolio homepage with profile and technologies sections</em></p>
<p>Our homepage is starting to take shape but the site still needs the most important part of any portfolio: projects.</p>
<p>To keep the project data organized, we’re going to use <strong>collections</strong>.</p>
<h2 id="heading-how-to-use-collections-in-eleventy">How to Use Collections in Eleventy</h2>
<p>Collections let you group related content together. In our portfolio we’re going to create a <code>projects</code> collection using Markdown files to store information about each individual project.</p>
<p>Inside the <code>src</code> directory, create a <code>projects</code> directory. We’re going to need a Markdown file for each project. As placeholders, we’ll use three projects that I’ve been meaning to build.</p>
<p>Josh W Comeau has some great advice on <a target="_blank" href="https://www.joshwcomeau.com/effective-portfolio/">building an effective developer portfolio</a> and he strongly recommends describing your personal projects with detailed case studies. So for each of our projects we’re going to have a case study laying out:</p>
<ul>
<li><p>What problem we solved</p>
</li>
<li><p>Why we chose these specific technologies</p>
</li>
<li><p>What challenges we faced</p>
</li>
<li><p>What lessons we learned</p>
</li>
</ul>
<p>Copy the following three sample projects into the <code>projects</code> directory:</p>
<p><code>catch-up.md</code></p>
<pre><code class="lang-markdown">---
title: "Catch Up"
summary: "Sometimes it's hard to keep in touch with friends and family. I made this app to remind me to schedule a call if we haven't talked in a while."
image: /images/catch-up.jpg
imageAlt: "Screenshots of catch up app"
tech:
<span class="hljs-bullet">  -</span> "Next.js"
<span class="hljs-bullet">  -</span> "Firebase"
<span class="hljs-bullet">  -</span> "Tailwind CSS"
siteUrl: "#"
<span class="hljs-section">repoUrl: "#"
---</span>

<span class="hljs-section">### Problem Solved</span>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tincidunt tortor aliquam nulla facilisi. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit. Condimentum lacinia quis vel eros donec ac odio tempor orci.

<span class="hljs-section">### Technologies Used</span>

Scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consequat ac felis donec et odio pellentesque diam volutpat commodo.

<span class="hljs-section">### Challenges Faced</span>

Eget mauris pharetra et ultrices. Molestie nunc non blandit massa enim nec. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Nulla at volutpat diam ut venenatis. Volutpat ac tincidunt vitae semper quis lectus nulla at.

<span class="hljs-section">### Lessons Learned</span>

Non blandit massa enim nec. Tempor commodo ullamcorper a lacus vestibulum sed. Et netus et malesuada fames ac turpis egestas integer eget. In ante metus dictum at tempor commodo. Eu scelerisque felis imperdiet proin fermentum leo.
</code></pre>
<p><code>sourdough-sensei.md</code></p>
<pre><code class="lang-markdown">---
title: "Sourdough Sensei"
summary: "Like a lot of people, I got really into sourdough in 2020. I made this app to help me bake delicious bread by putting all my recipes and schedules in one place."
image: /images/sourdough-sensei.jpg
imageAlt: "Screenshots of sourdough bread app"
tech:
<span class="hljs-bullet">  -</span> "React.js"
<span class="hljs-bullet">  -</span> "Firebase"
<span class="hljs-bullet">  -</span> "Tailwind CSS"
siteUrl: "#"
<span class="hljs-section">repoUrl: "#"
---</span>

<span class="hljs-section">### Problem Solved</span>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tincidunt tortor aliquam nulla facilisi. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit. Condimentum lacinia quis vel eros donec ac odio tempor orci.

<span class="hljs-section">### Technologies Used</span>

Scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consequat ac felis donec et odio pellentesque diam volutpat commodo.

<span class="hljs-section">### Challenges Faced</span>

Eget mauris pharetra et ultrices. Molestie nunc non blandit massa enim nec. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Nulla at volutpat diam ut venenatis. Volutpat ac tincidunt vitae semper quis lectus nulla at.

<span class="hljs-section">### Lessons Learned</span>

Non blandit massa enim nec. Tempor commodo ullamcorper a lacus vestibulum sed. Et netus et malesuada fames ac turpis egestas integer eget. In ante metus dictum at tempor commodo. Eu scelerisque felis imperdiet proin fermentum leo.
</code></pre>
<p><code>spellbook.md</code></p>
<pre><code class="lang-markdown">---
title: "Spellbook"
summary: "I'm a huge Dungeons and Dragons fan, but keeping my spells straight has always been a challenge. I built this app to put all the information I need at my fingertips."
image: /images/spellbook.jpg
imageAlt: "Screenshots of DnD project"
tech:
<span class="hljs-bullet">  -</span> "Next.js"
<span class="hljs-bullet">  -</span> "Firebase"
<span class="hljs-bullet">  -</span> "Tailwind CSS"
siteUrl: "#"
<span class="hljs-section">repoUrl: "#"
---</span>

<span class="hljs-section">### Problem Solved</span>

Yes, I could have just used DnD Beyond. But where's the fun in that? Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tincidunt tortor aliquam nulla facilisi. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit. Condimentum lacinia quis vel eros donec ac odio tempor orci.

<span class="hljs-section">### Technologies Used</span>

Scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consequat ac felis donec et odio pellentesque diam volutpat commodo.

<span class="hljs-section">### Challenges Faced</span>

Eget mauris pharetra et ultrices. Molestie nunc non blandit massa enim nec. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Nulla at volutpat diam ut venenatis. Volutpat ac tincidunt vitae semper quis lectus nulla at.

<span class="hljs-section">### Lessons Learned</span>

Non blandit massa enim nec. Tempor commodo ullamcorper a lacus vestibulum sed. Et netus et malesuada fames ac turpis egestas integer eget. In ante metus dictum at tempor commodo. Eu scelerisque felis imperdiet proin fermentum leo.
</code></pre>
<p>Just like with templates, the frontmatter at the top of these files makes values available that you can inject into your templates.</p>
<p>Since these Markdown files are ultimately inside the <code>src</code> directory, Eleventy will treat them as templates and create a HTML page from each file. Their URL will be in the format <code>/subdirectory_name/filename</code>, for example <code>/projects/sourdough-sensei</code>.</p>
<p>But Eleventy won't know what layout to use for these pages since they don't yet have a <code>layout</code> value in their frontmatter.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-19-08-18-Screenshot.png" alt="sourdough-sensei page without layout or frontmatter data" width="600" height="400" loading="lazy"></p>
<p><em>sourdough-sensei page without layout or frontmatter data</em></p>
<p>Right now these files aren’t a collection. Collections are defined by sharing a <code>tags</code> value, such as <code>“tags”: “projects”</code>.</p>
<p>Every file with the <code>projects</code> tag will be included in the <code>projects</code> collection.</p>
<p>Since we only have three projects, we could include a <code>tags</code> value in the frontmatter of our three Markdown files.</p>
<p>But if we had a site with a lot of content – for example dozens of blog posts, recorded talks, and tutorials that all shared dozens of tags between them – this could become difficult to manage. This is where <strong>directory data files</strong> are useful.</p>
<h3 id="heading-how-to-use-directory-data-files">How to Use Directory Data Files</h3>
<p>If you have certain values that are shared by every file in a folder, you can put these values in a directory data file.</p>
<p>Inside the <code>projects</code> directory, create a <code>projects.json</code> file. A directory data file should have the same name as the collection it’s attached to.</p>
<p>Any frontmatter fields that are shared by all the projects files should go in the <code>projects.json</code> directory data file:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"layout"</span>: <span class="hljs-string">"project.njk"</span>,
  <span class="hljs-attr">"tags"</span>: <span class="hljs-string">"projects"</span>
}
</code></pre>
<p>The <code>layout</code> value means that every project will use the same layout (we’re going to create this <code>project.njk</code> file in a moment). The <code>tags</code> value is what turns them into the <code>projects</code> collection that we can use in our templates.</p>
<h2 id="heading-how-to-use-collections-in-templates">How to Use Collections in Templates</h2>
<p>We’re now going to use the <code>projects</code> collection to:</p>
<ul>
<li><p>Add a projects section to our homepage</p>
</li>
<li><p>Create a Projects page</p>
</li>
<li><p>Create a case study page for each project</p>
</li>
</ul>
<p>To include data from a collection on a page of your site, you need to reference the <code>collections</code> object in a template.</p>
<p>We can use Nunjucks to loop over the collection and output its contents. To access a frontmatter value from a <code>project</code> in the <code>projects</code> collection, we use <code>project.data</code>.</p>
<p>For example:</p>
<pre><code class="lang-python">{% <span class="hljs-keyword">for</span> project <span class="hljs-keyword">in</span> collections.projects %}
{{ project.data.title }}
{% endfor %}
</code></pre>
<p>In the <code>_includes</code> directory, create <code>project.njk</code>, <code>project-card.njk</code> and <code>project-grid.njk</code> files.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/includes.PNG" alt="_includes directory structure." width="600" height="400" loading="lazy"></p>
<p>_<em>includes directory structure</em></p>
<p>We’ll use <code>project.njk</code> to create a page for each of our projects.</p>
<p>Since these pages are generated from templates, we can access their frontmatter values directly, such as <code>title</code>, <code>image</code>, <code>imageAlt</code>, and <code>content</code> for the main content of the Markdown file.</p>
<pre><code class="lang-python">---
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__heading</span>"&gt;{{ <span class="hljs-title">title</span> }}&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__image</span>-<span class="hljs-title">wrapper</span>"&gt;
      &lt;<span class="hljs-title">img</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">imageAlt</span> }}"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__content</span> <span class="hljs-title">prose</span>"&gt;
    {{ <span class="hljs-title">content</span> | <span class="hljs-title">safe</span> }}
  &lt;/<span class="hljs-title">div</span>&gt;
&lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
<p><code>project-grid.njk</code> and <code>project-card.njk</code> will form the list of projects on our portfolio homepage and Projects page.</p>
<p><code>project-grid.njk</code> will loop over the <code>projects</code> collection and insert a <code>project-card</code> partial for each project in the collection.</p>
<p>Add the following content to <code>project-grid.njk</code>:</p>
<pre><code class="lang-python">&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">projects</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__heading</span>"&gt;<span class="hljs-title">Recent</span> <span class="hljs-title">projects</span>&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">grid</span>"&gt;
    {% <span class="hljs-title">for</span> <span class="hljs-title">project</span> <span class="hljs-title">in</span> <span class="hljs-title">collections</span>.<span class="hljs-title">projects</span> %}
      {% <span class="hljs-title">include</span> "<span class="hljs-title">project</span>-<span class="hljs-title">card</span>.<span class="hljs-title">njk</span>" %}
    {% <span class="hljs-title">endfor</span> %}
  &lt;/<span class="hljs-title">div</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>Add the following content to <code>project-card.njk</code>:</p>
<pre><code class="lang-python">&lt;article <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__image</span>-<span class="hljs-title">wrapper</span>"&gt;
    &lt;<span class="hljs-title">img</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">imageAlt</span> }}"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__body</span>"&gt;
    &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__tags</span>"&gt;
      {% <span class="hljs-title">for</span> <span class="hljs-title">tag</span> <span class="hljs-title">in</span> <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">tech</span> %}
        &lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__tag</span>"&gt;{{ <span class="hljs-title">tag</span> }}&lt;/<span class="hljs-title">span</span>&gt;
      {% <span class="hljs-title">endfor</span> %}
    &lt;/<span class="hljs-title">div</span>&gt;
    &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__title</span>"&gt;
      &lt;<span class="hljs-title">a</span> <span class="hljs-title">href</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">url</span> }}"&gt;{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">title</span> }}&lt;/<span class="hljs-title">a</span>&gt;
    &lt;/<span class="hljs-title">h3</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__summary</span>"&gt;{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">summary</span> }}&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__link</span>" <span class="hljs-title">href</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">url</span> }}"&gt;<span class="hljs-title">Read</span> <span class="hljs-title">project</span> <span class="hljs-title">case</span> <span class="hljs-title">study</span> 
      &lt;<span class="hljs-title">svg</span> <span class="hljs-title">xmlns</span>="<span class="hljs-title">http</span>:</span>//www.w3.org/<span class="hljs-number">2000</span>/svg<span class="hljs-string">" class="</span>project-card__link-icon<span class="hljs-string">" viewBox="</span><span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">20</span> <span class="hljs-number">20</span><span class="hljs-string">" fill="</span>currentColo<span class="hljs-string">r"&gt;
        &lt;path fill-rule="</span>evenodd<span class="hljs-string">" d="</span>M7<span class="hljs-number">.293</span> <span class="hljs-number">14.707</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">010</span><span class="hljs-number">-1.414L</span>10<span class="hljs-number">.586</span> <span class="hljs-number">10</span> <span class="hljs-number">7.293</span> <span class="hljs-number">6.707</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">011.414</span><span class="hljs-number">-1.414l</span>4 <span class="hljs-number">4</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">010</span> <span class="hljs-number">1.414l</span><span class="hljs-number">-4</span> <span class="hljs-number">4</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">01</span><span class="hljs-number">-1.414</span> <span class="hljs-number">0</span>z<span class="hljs-string">" clip-rule="</span>evenodd<span class="hljs-string">" /&gt;
      &lt;/svg&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/article&gt;</span>
</code></pre>
<p>Since <code>project-card.njk</code> is accessing frontmatter values from a member of a collection, we need to use <code>project.data</code> to access these values in the template. Eleventy also generates a <code>project.url</code> value that we can use to link to the project's generated page.</p>
<p>In <code>index.njk</code>, add <code>{% include "project-grid.njk" %}</code> underneath the profile and technologies partials.</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

{% include <span class="hljs-string">"profile.njk"</span> %}
{% include <span class="hljs-string">"technologies.njk"</span> %}
{% include <span class="hljs-string">"project-grid.njk"</span> %}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-19-41-45-Eleventy-Portfolio.png" alt="Grid of project cards on homepage." width="600" height="400" loading="lazy"></p>
<p><em>Grid of project cards on homepage</em></p>
<p>Next we're going to create a Projects page. In the <code>src</code> directory, create a <code>projects.njk</code> file with the following contents:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;h2 <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">projects__heading</span>"&gt;<span class="hljs-title">Recent</span> <span class="hljs-title">projects</span>&lt;/<span class="hljs-title">h2</span>&gt;
&lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">list</span>"&gt;
  {% <span class="hljs-title">for</span> <span class="hljs-title">project</span> <span class="hljs-title">in</span> <span class="hljs-title">collections</span>.<span class="hljs-title">projects</span> %}
    {% <span class="hljs-title">include</span> "<span class="hljs-title">project</span>-<span class="hljs-title">card</span>.<span class="hljs-title">njk</span>" %}
  {% <span class="hljs-title">endfor</span> %}
&lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-19-25-32-Eleventy-Portfolio.png" alt="Projects page." width="600" height="400" loading="lazy"></p>
<p><em>Projects page</em></p>
<p>The projects are now being displayed on our homepage as well as the projects page, and each project now has its own page with its case study.</p>
<p>We could stop here, but there are a few more Eleventy features that will make our portfolio site even better, namely <strong>shortcodes</strong> and <strong>plugins</strong>.</p>
<h3 id="heading-how-to-use-shortcodes">How to Use Shortcodes</h3>
<p>A shortcode is a way to inject reusable content (often a JavaScript string template literal) into your templates.</p>
<p>We’re going to create a simple <code>year</code> shortcode that outputs the current year so that the footer in our portfolio site is always up to date.</p>
<p>Add the following line to the configuration function in <code>.eleventy.js</code>.</p>
<pre><code class="lang-javascript">eleventyConfig.addShortcode(<span class="hljs-string">"year"</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear()}</span>`</span>);
</code></pre>
<p>When you use the shortcode in a template the function will be run and the <code>year</code> value will be injected into the template.</p>
<p>In <code>footer.njk</code> use <code>{% year %}</code> to access the <code>year</code> shortcode.</p>
<pre><code class="lang-python">&lt;footer <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">footer</span>"&gt;
  &lt;<span class="hljs-title">p</span>&gt;&amp;<span class="hljs-title">copy</span>; <span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span> {% <span class="hljs-title">year</span> %}&lt;/<span class="hljs-title">p</span>&gt;
&lt;/<span class="hljs-title">footer</span>&gt;</span>
</code></pre>
<p>You might need to restart your development server for it to recognize the shortcode.</p>
<p>Now whenever you trigger a build of your site in the future, your footer will always show the correct year.</p>
<p>Shortcodes can do a lot more than this. Next, we’re going to use the Eleventy Image plugin, which uses shortcodes, to optimize our site’s images and improve our page load speed.</p>
<h3 id="heading-how-to-use-the-eleventy-image-plugin">How to Use the Eleventy Image Plugin</h3>
<p>Eleventy has a number of official plugins, from ones to check your writing for inclusive language to others that let you leverage Serverless functions.</p>
<p>The Image plugin is particularly useful since images are often the largest resource your site loads. It optimizes your images so your site uses the appropriate size and format for the user's browser, saving bandwidth for your user and making your site load faster.</p>
<p>First we need to install the Image plugin from npm. In the root of your project, run:</p>
<pre><code class="lang-python">npm install @<span class="hljs-number">11</span>ty/eleventy-img
</code></pre>
<p>At the top of <code>.eleventy.js</code>, we’re going to import the Image plugin and configure the shortcode that the plugin will use to optimize our images.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Image = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@11ty/eleventy-img"</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">imageShortcode</span>(<span class="hljs-params">src, alt, sizes</span>) </span>{
  <span class="hljs-keyword">let</span> metadata = <span class="hljs-keyword">await</span> Image(<span class="hljs-string">`./src<span class="hljs-subst">${src}</span>`</span>, {
    <span class="hljs-attr">widths</span>: [<span class="hljs-number">300</span>, <span class="hljs-number">800</span>, <span class="hljs-literal">null</span>],
    <span class="hljs-attr">formats</span>: [<span class="hljs-string">"avif"</span>, <span class="hljs-string">"jpeg"</span>],
    <span class="hljs-attr">urlPath</span>: <span class="hljs-string">"/images/"</span>,
    <span class="hljs-attr">outputDir</span>: <span class="hljs-string">"./public/images/"</span>
  });

  <span class="hljs-keyword">let</span> imageAttributes = {
    alt,
    sizes,
    <span class="hljs-attr">loading</span>: <span class="hljs-string">"lazy"</span>,
    <span class="hljs-attr">decoding</span>: <span class="hljs-string">"async"</span>
  };

  <span class="hljs-keyword">return</span> Image.generateHTML(metadata, imageAttributes);
}
</code></pre>
<p>The image shortcode takes in arguments for <code>src</code>, <code>alt</code> and <code>sizes</code>. These will be the URL for the image, the text for the image’s alt tag, and the sizes that are used to display different sized images at different screen sizes.</p>
<p>The <code>widths</code> property specifies what size images the plugin will generate. In this case, 300px, 800px, and the image's original size.</p>
<p>The <code>formats</code> property specifies which image formats to generate. Here we're using avif (which produces high quality images at low file sizes) with jpeg as a fallback for browsers that don't support avif.</p>
<p><code>urlPath</code> and <code>outputDir</code> tell the plugin where to get the images from and where to output the optimized images to.</p>
<p>The plugin adds <code>loading</code> and <code>decoding</code> attributes to the generated HTML to lazy-load the images and decode them asynchronously, both of which will help with page load times.</p>
<p>Next, we’re going to include the shortcode in our configuration function. We'll call it <code>EleventyImage</code> for the sake of clarity.</p>
<pre><code class="lang-javascript">eleventyConfig.addNunjucksAsyncShortcode(<span class="hljs-string">"EleventyImage"</span>, imageShortcode);
</code></pre>
<p>Notice that we’re using <code>addNunjucksAsyncShortcode</code> rather than <code>addShortcode</code>. This is because the image generation process is asynchronous. It will take some amount of time to generate different image sizes and formats and we want our shortcode to wait until these have all been generated before it injects the finished HTML into our templates.</p>
<p>Since our shortcode is asynchronous, we’re going to run into an issue with using this shortcode inside a Nunjucks for loop. We need to use <code>asyncEach</code>, the asynchronous version of Nunjuck’s <code>for</code>.</p>
<p>In <code>projects.njk</code> and <code>project-grid.njk</code>, replace this:</p>
<pre><code class="lang-python">{% <span class="hljs-keyword">for</span> project <span class="hljs-keyword">in</span> collections.projects %}
{% include <span class="hljs-string">"project-card.njk"</span> %}
{% endfor %}
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% asyncEach project <span class="hljs-keyword">in</span> collections.projects %}
{% include <span class="hljs-string">"project-card.njk"</span> %}
{% endeach %}
</code></pre>
<p>Now, in <code>project.njk</code> we can replace this:</p>
<pre><code class="lang-python">&lt;img <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">imageAlt</span> }}"&gt;</span>
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% EleventyImage image, imageAlt, <span class="hljs-string">"(min-width: 30em) 50vw, 100vw"</span> %}
</code></pre>
<p>The <code>image</code>, <code>imageAlt</code> and <code>"(min-width: 30em) 50vw, 100vw"</code> values are the <code>src</code>, <code>alt</code> and <code>sizes</code> parameters for the Image shortcode.</p>
<p>Next, in <code>project-card.njk</code>, we can replace this:</p>
<pre><code class="lang-python">&lt;img <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">imageAlt</span> }}"&gt;</span>
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% EleventyImage project.data.image, project.data.imageAlt, <span class="hljs-string">"(min-width: 30em) 50vw, 100vw"</span> %}
</code></pre>
<p>Finally, in <code>profile.njk</code> we can replace this:</p>
<pre><code class="lang-python">&lt;img <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">profile__image</span>" <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">profile</span>.<span class="hljs-title">jpg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span>, <span class="hljs-title">Software</span> <span class="hljs-title">Developer</span>"&gt;</span>
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% EleventyImage <span class="hljs-string">"/images/profile.jpg"</span>, <span class="hljs-string">"Marie Jackson, Software Developer"</span>, <span class="hljs-string">"(min-width: 16em) 50vw, 100vw"</span> %}
</code></pre>
<p>When our site builds, the Eleventy Image plugin will do a couple of things:</p>
<ul>
<li><p>there will be multiple formats and sizes for every image in <code>public/images</code></p>
</li>
<li><p>our generated HTML will now use the <code>&lt;picture&gt;</code> element</p>
</li>
<li><p>the <code>&lt;img&gt;</code> tags will have <code>loading="lazy"</code> and <code>decode="async"</code> attributes</p>
</li>
</ul>
<p>Now our site will serve the optimal image format and size depending on the browser and screen size of the site visitor. And images will be lazy loaded as they are about to enter the viewport.</p>
<p>If we use the network tab in a browser's developer tools, we can test the difference. On an iPhone 12, the unoptimized image on one of our project pages would be 30.37KB, while the image optimized by the Image plugin is just 6.01KB, an 80% saving!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/unoptimized.PNG" alt="Unoptimized image on mobile - 30.37KB." width="600" height="400" loading="lazy"></p>
<p><em>Unoptimized image on mobile - 30.37KB</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/optimized.PNG" alt="Optimized image on mobile 6.01KB." width="600" height="400" loading="lazy"></p>
<p><em>Optimized image on mobile 6.01KB</em></p>
<p>We’re almost ready to deploy our site. But before we do that, we need to complete our contact form.</p>
<h2 id="heading-how-to-a-build-contact-form-with-netlify-forms">How to a Build Contact Form with Netlify Forms</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-17-08-Eleventy-Portfolio-1.png" alt="Contact page" width="600" height="400" loading="lazy"></p>
<p><em>Contact page</em></p>
<p>Eleventy is a <strong>static</strong> site generator. But Eleventy works really well with the Jamstack architecture, where you statically generate as much of a site as possible in advance and use APIs and third-party services to add dynamic content and functionality.</p>
<p>In the past, if you wanted to have a contact form on your website, you would need some sort of server, such as a PHP app, to process the form submission.</p>
<p>We’re going to use Netlify Forms to add a contact form to our portfolio without needing to manage a server to handle the submitted forms.</p>
<p>To make this work, we need to make sure our form has two attributes. The most important one is <code>data-netlify="true"</code>. The other is <code>action="/success"</code>.</p>
<pre><code class="lang-python">&lt;form <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">form</span>" <span class="hljs-title">name</span>="<span class="hljs-title">contact</span>" <span class="hljs-title">action</span>="/<span class="hljs-title">success</span>" <span class="hljs-title">method</span>="<span class="hljs-title">POST</span>" <span class="hljs-title">data</span>-<span class="hljs-title">netlify</span>="<span class="hljs-title">true</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourName</span>"&gt;<span class="hljs-title">Name</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">name</span>" <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">id</span>="<span class="hljs-title">yourName</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourEmail</span>"&gt;<span class="hljs-title">Email</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">email</span>" <span class="hljs-title">type</span>="<span class="hljs-title">email</span>"  <span class="hljs-title">id</span>="<span class="hljs-title">yourEmail</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">message</span>"&gt;<span class="hljs-title">Message</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">textarea</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">message</span>" <span class="hljs-title">id</span>="<span class="hljs-title">message</span>" <span class="hljs-title">rows</span>="4" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;&lt;/<span class="hljs-title">textarea</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
    &lt;<span class="hljs-title">button</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__button</span>" <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>"&gt;<span class="hljs-title">Let</span>'<span class="hljs-title">s</span> <span class="hljs-title">talk</span>&lt;/<span class="hljs-title">button</span>&gt;
&lt;/<span class="hljs-title">form</span>&gt;</span>
</code></pre>
<p>By having a <code>data-netlify="true"</code> attribute on our contact form, when the site is deployed to Netlify, Netlify will recognize this and take over handling the form submission.</p>
<p>By default, when someone completes a Netlify form, they will get a generically styled success message with a link back to the form page. But we can direct them to a custom page by including an <code>action</code> attribute on our form.</p>
<p>The <code>action="/success"</code> attribute means that when the form submits, the user will be redirected to a "success" page on your site (you can give this page a different name if you like). So we had better build that page now.</p>
<p>In the <code>src</code> directory, create a <code>success.njk</code> file with the following content:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">container</span> <span class="hljs-title">text</span>-<span class="hljs-title">center</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">heading</span>--<span class="hljs-title">main</span>"&gt;<span class="hljs-title">Thanks</span> <span class="hljs-title">for</span> <span class="hljs-title">getting</span> <span class="hljs-title">in</span> <span class="hljs-title">touch</span>!&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">I</span>'<span class="hljs-title">ll</span> <span class="hljs-title">respond</span> <span class="hljs-title">as</span> <span class="hljs-title">soon</span> <span class="hljs-title">as</span> <span class="hljs-title">I</span> <span class="hljs-title">can</span>.&lt;<span class="hljs-title">p</span>&gt;
&lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
<p>Once we deploy the site to Netlify, any submitted forms will show up in the Netlify interface. So let’s finally deploy our portfolio site.</p>
<h2 id="heading-how-to-deploy-to-netlify">How to Deploy to Netlify</h2>
<p>You can deploy an Eleventy site on any static hosting platform: Netlify, Vercel, GitHub Pages, even an AWS S3 bucket.</p>
<p>I'll show you how to deploy to Netlify since we're using Netlify Forms for our contact form. On another hosting platform, you could use a Serverless function to handle submitting the form and sending an email.</p>
<p>If you don't already have a Netlify account, go to <a target="_blank" href="https://www.netlify.com/">netlify.com</a> and create a free one.</p>
<p>Netlify will give you the option to:</p>
<ol>
<li><p>Import an existing project</p>
</li>
<li><p>Start from a template</p>
</li>
<li><p>Deploy manually</p>
</li>
</ol>
<p>We already have our portfolio site, so we don't need a template.</p>
<p>I'll walk you through the two other options.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-25-15-Deploy-your-first-project-Netlify.png" alt="Netlify project start screen." width="600" height="400" loading="lazy"></p>
<p><em>Netlify project start screen</em></p>
<h3 id="heading-option-1-how-to-deploy-manually">Option 1 – How to Deploy Manually</h3>
<p>If you're not comfortable with Git and GitHub, Netlify lets you drag and drop to upload a project into their interface.</p>
<p>On your command line, run <code>npm run build</code> or <code>eleventy</code> to build your site.</p>
<p>Now upload the site's <code>public</code> directory to Netlify's file upload interface. In a few moments Netlify will have the site live on a URL that you can visit.</p>
<p>If you want to make future changes to your deployed site, click on "Deploys" and scroll down to find the file uploader.</p>
<p>You can rebuild your site locally and upload the new version of your <code>public</code> folder to Netlify whenever you want.</p>
<h3 id="heading-option-2-how-to-import-a-project-from-git">Option 2 – How to Import a Project from Git</h3>
<p>If you are familiar with Git and GitHub, commit your code and push it to GitHub. Then click on the "Import from Git" button.</p>
<p>Netlify will ask you to connect a Git provider. Choose GitHub and authorize Netlify to access your GitHub repositories.</p>
<p>Choose the repository that holds your portfolio site. You can search for "eleventy", or whatever name you gave it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-44-56-Import-an-existing-project-from-a-Git-repository-Netlify.png" alt="Netlify import project interface." width="600" height="400" loading="lazy"></p>
<p><em>Netlify import project interface</em></p>
<p>Netlify will detect that this is an Eleventy project and will ask you to confirm the basic build settings.</p>
<p>Make sure the build command is either <code>npm run build</code> or <code>eleventy</code>.</p>
<p>Under "Publish directory", enter <code>public</code> instead of <code>_site</code>.</p>
<p>Now click the "Deploy site" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-46-55-Import-an-existing-project-from-a-Git-repository-Netlify.png" alt="Netlify build settings page." width="600" height="400" loading="lazy"></p>
<p><em>Netlify build settings page</em></p>
<p>In a few moments Netlify will tell you that your site is live and give you a URL for it.</p>
<p>Once your site is live, if go to the Contact page, fill out the form, and submit it. You'll be redirected to the custom success page that you made.</p>
<p>If you click on "Forms" in the Netlify interface, you'll be brought to the Netlify Forms dashboard.</p>
<p>The form will have whatever name you used in the <code>name</code> attribute on your contact form, in this case "contact".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-55-09-Forms-remarkable-blini-2319ee.png" alt="Netlify forms dashboard." width="600" height="400" loading="lazy"></p>
<p><em>Netlify forms dashboard</em></p>
<p>Congratulations, you've built and deployed an Eleventy portfolio site. 🥳🎉🎉🎉</p>
<p>Feel free to use this project as a template for your own portfolio and customize it any way you'd like. So many portfolios look similar, so it's always good when a portfolio shows off your personality and passions.</p>
<h2 id="heading-where-to-take-it-from-here">Where to Take it from Here</h2>
<p>This tutorial has hopefully taught you the basics of Eleventy, and how to combine data and templates to make fast sites without a whole lot of tooling or configuration.</p>
<p>If you'd like to take your Eleventy journey further, the <a target="_blank" href="https://www.11ty.dev/docs/">Eleventy docs</a> are very good. There's lots more to learn about manipulating data, not to mention adding personalized content and dynamic interactivity with Serverless and Edge Functions.</p>
<p><a target="_blank" href="https://11ty.rocks/">11ty.rocks</a> by Stephanie Eckles is also a great resource, with practical tips and helpful tutorials on all sorts of Eleventy features.</p>
<p>I hope this guide has been helpful and made you excited to learn more about Eleventy, static site generators, and the Jamstack.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Manage PostgreSQL Databases from the Command Line with psql ]]>
                </title>
                <description>
                    <![CDATA[ Now is a great time to learn relational databases and SQL. From web development to data science, they are used everywhere. In the Stack Overflow 2021 Survey, 4 out of the top 5 database technologies used by professional developers were relational dat... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/manage-postgresql-with-psql/</link>
                <guid isPermaLink="false">66d45ee547a8245f78752a38</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                    <category>
                        <![CDATA[ terminal ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gerard Hynes ]]>
                </dc:creator>
                <pubDate>Tue, 07 Jun 2022 15:29:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/05/manage-postgreSQL-with-psql.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Now is a great time to learn relational databases and SQL. From web development to data science, they are used everywhere.</p>
<p>In the <a target="_blank" href="https://insights.stackoverflow.com/survey/2021#most-popular-technologies-database-prof">Stack Overflow 2021 Survey</a>, 4 out of the top 5 database technologies used by professional developers were relational database management systems.</p>
<p>PostgreSQL is an excellent choice as a first relational database management system to learn.</p>
<ol>
<li><p>It’s widely used in industry, including at <a target="_blank" href="https://stackshare.io/postgresql">Uber, Netflix, Instagram, Spotify, and Twitch</a>.</p>
</li>
<li><p>It’s open source, so you won’t be locked into a particular vendor.</p>
</li>
<li><p>It's more than 25 years old, and in that time it has earned a reputation for stability and reliability.</p>
</li>
</ol>
<p>Whether you’re learning from the freeCodeCamp <a target="_blank" href="https://www.freecodecamp.org/learn/relational-database/">Relational Database Certification</a> or trying out PostgreSQL on your own computer, you need a way to create and manage databases, insert data into them, and query data from them.</p>
<p>While there are several graphical applications for interacting with PostgreSQL, using psql and the command line is probably the most direct way to communicate with your database.</p>
<h2 id="heading-what-is-psql">What is psql?</h2>
<p>psql is a tool that lets you interact with PostgreSQL databases through a terminal interface. When you install PostgreSQL on a machine, psql is automatically included.</p>
<p>psql lets you write SQL queries, send them to PostgreSQL, and view the results. It also lets you use meta-commands (which start with a backslash) for administering the databases. You can even write scripts and automate tasks relating to your databases.</p>
<p>Now, running a database on your local computer and using the command line can seem intimidating at first. I’m here to tell you it’s really not so bad. This guide will teach you the basics of managing PostgreSQL databases from the command line, including how to create, manage, back up, and restore databases.</p>
<h2 id="heading-prerequisite-install-postgresql">Prerequisite – Install PostgreSQL</h2>
<p>If you haven’t already installed PostgreSQL on your computer, follow the instructions for your operating system on the <a target="_blank" href="https://www.postgresql.org/download/">official PostgreSQL documentation</a>.</p>
<p>When you install PostgreSQL, you will be asked for a password. Keep this in a safe place as you’ll need it to connect to any databases you create.</p>
<h2 id="heading-how-to-connect-to-a-database">How to Connect to a Database</h2>
<p>You have two options when using psql to connect to a database: you can connect via the command line or by using the psql application. Both provide pretty much the same experience.</p>
<h3 id="heading-option-1-connect-to-a-database-with-the-command-line">Option 1 – Connect to a database with the command line</h3>
<p>Open a terminal. You can make sure psql is installed by typing <code>psql --version</code>. You should see <code>psql (PostgreSQL) version_number</code>, where <code>version_number</code> is the version of PostgreSQL that’s installed on your machine. In my case, it's 14.1.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-4.png" alt="Checking psql version via the command line" width="600" height="400" loading="lazy"></p>
<p><em>Checking psql version via the command line</em></p>
<p>The pattern for connecting to a database is:</p>
<pre><code class="lang-python">psql -d database_name -U username
</code></pre>
<p>The <code>-d</code> flag is shorter alternative for <code>--dbname</code> while <code>-U</code> is an alternative for <code>--username</code>.</p>
<p>When you installed PostgreSQL, a default database and user were created, both called <code>postgres</code>. So enter <code>psql -d postgres -U postgres</code> to connect to the <code>postgres</code> database as the <code>postgres</code> superuser.</p>
<pre><code class="lang-python">psql -d postgres -U postgres
</code></pre>
<p>You will be prompted for a password. Enter the password you chose when you installed PostgreSQL on your computer. Your terminal prompt will change to show that you’re now connected to the <code>postgres</code> database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-5.png" alt="Connecting to a database from the command line with psql" width="600" height="400" loading="lazy"></p>
<p><em>Connecting to a database from the command line with psql</em></p>
<p>If you want to directly connect to a database as yourself (rather than as the <code>postgres</code> superuser), enter your system username as the username value.</p>
<h3 id="heading-option-2-connect-to-a-database-with-the-psql-application">Option 2 – Connect to a database with the psql application</h3>
<p>Launch the psql application – it'll be called "SQL Shell (psql)". You will be prompted for a server, a database, a port and a username. You can just press enter to select the default values, which are <code>localhost</code>, <code>postgres</code>, <code>5432</code>, and <code>postgres</code>.</p>
<p>Next, you’ll be prompted for the password you chose when you installed PostgreSQL. Once you enter this, your terminal prompt will change to show that you’re connected to the <code>postgres</code> database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-2.png" alt="Connecting to a database with the psql application" width="600" height="400" loading="lazy"></p>
<p><em>Connecting to a database with the psql application</em></p>
<p><strong>Note:</strong> If you’re on Windows you might see a warning like “Console code page (850) differs from Windows code page (1252) 8-bit characters might not work correctly. See psql reference page 'Notes for Windows users' for details.” You don’t need to worry about this at this stage. If you want to read more about it, see the <a target="_blank" href="https://www.postgresql.org/docs/current/app-psql.html">psql documentation</a>.</p>
<h2 id="heading-how-to-get-help-in-psql">How to Get Help in psql</h2>
<p>To see a list of all psql meta-commands, and a brief summary of what they do, use the <code>\?</code> command.</p>
<pre><code class="lang-python">\?
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-6.png" alt="psql's help command" width="600" height="400" loading="lazy"></p>
<p><em>psql's help command</em></p>
<p>If you want help with a PostgreSQL command, use <code>\h</code> or <code>\help</code> and the command.</p>
<pre><code class="lang-python">\h COMMAND
</code></pre>
<p>This will give you a description of the command, its syntax (with optional parts in square brackets), and a URL for the relevant part of the PostgreSQL documentation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-7.png" alt="psql describing the DROP TABLE statement" width="600" height="400" loading="lazy"></p>
<p><em>psql describing the DROP TABLE statement</em></p>
<h2 id="heading-how-to-quit-a-command-in-psql">How to Quit a Command in psql</h2>
<p>If you’ve run a command that’s taking a long time or printing too much information to the console, you can quit it by typing <code>q</code>.</p>
<pre><code class="lang-python">q
</code></pre>
<h2 id="heading-how-to-create-a-database">How to Create a Database</h2>
<p>Before you can manage any databases, you’ll need to create one.</p>
<p><strong>Note:</strong> SQL commands should end with a semicolon, while meta-commands (which start with a backslash) don’t need to.</p>
<p>The SQL command to create a database is:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">DATABASE</span> database_name;
</code></pre>
<p>For this guide, we’re going to be working with book data, so let’s create a database called <code>books_db</code>.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">DATABASE</span> books_db;
</code></pre>
<h2 id="heading-how-to-list-databases">How to List Databases</h2>
<p>You can view a list of all available databases with the list command.</p>
<pre><code class="lang-python">\l
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-8.png" alt="Listing all databases" width="600" height="400" loading="lazy"></p>
<p><em>Listing all databases</em></p>
<p>You should see <code>books_db</code>, as well as <code>postgres</code>, <code>template0</code>, and <code>template1</code>. (The <code>CREATE DATABASE</code> command actually works by copying the standard database, called <code>template1</code>. You can read more about this in the <a target="_blank" href="https://www.postgresql.org/docs/current/manage-ag-templatedbs.html">PostgreSQL documentation</a>.)</p>
<p>Using <code>\l+</code> will display additional information, such as the size of the databases and their tablespaces (the location in the filesystem where the files representing the database will be stored).</p>
<pre><code class="lang-python">\l+
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-22.png" alt="Listing all databases with additional information" width="600" height="400" loading="lazy"></p>
<p><em>Listing all databases with additional information</em></p>
<h2 id="heading-how-to-switch-databases">How to Switch Databases</h2>
<p>You’re currently still connected to the default <code>postgres</code> database. To connect to a database or to switch between databases, use the <code>\c</code> command.</p>
<pre><code class="lang-python">\c database_name
</code></pre>
<p>So <code>\c books_db</code> will connect you to the <code>books_db</code> database. Note that your terminal prompt changes to reflect the database you’re currently connected to.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-9.png" alt="Switching databases" width="600" height="400" loading="lazy"></p>
<p><em>Switching databases</em></p>
<h2 id="heading-how-to-delete-a-database">How to Delete a Database</h2>
<p>If you want to delete a database, use the <code>DROP DATABASE</code> command.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">DATABASE</span> database_name;
</code></pre>
<p>You will only be allowed to delete a database if you are a superuser, such as <code>postgres</code>, or if you are the database’s owner.</p>
<p>If you try to delete a database that doesn’t exist, you will get an error. Use <code>IF EXISTS</code> to get a notice instead.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">DATABASE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> database_name;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-10.png" alt="Deleting a database" width="600" height="400" loading="lazy"></p>
<p><em>Deleting a database</em></p>
<p>You can’t delete a database that has active connections. So if you want to delete the database you are currently connected to, you’ll need to switch to another database.</p>
<h2 id="heading-how-to-create-tables">How to Create Tables</h2>
<p>Before we can manage tables, we need to create a few and populate them with some sample data.</p>
<p>The command to create a table is:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> table_name();
</code></pre>
<p>This will create an empty table. You can also pass column values into the parentheses to create a table with columns. At the very least, a basic table should have a Primary Key (a unique identifier to tell each row apart) and a column with some data in it.</p>
<p>For our <code>books_db</code>, we’ll create a table for authors and another for books. For authors, we’ll record their first name and last name. For books, we’ll record the title and the year they were published.</p>
<p>We’ll make sure that the authors’ <code>first_name</code> and <code>last_name</code> and the books’ <code>title</code> aren’t null, since this is pretty vital information to know about them. To do this we include the <code>NOT NULL</code> constraint.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">authors</span>(
    author_id <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>, 
    first_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>, 
    last_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
);

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> books(
    book_id <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>, 
    title <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>, 
    published_year <span class="hljs-built_in">INT</span>
);
</code></pre>
<p>You will see <code>CREATE TABLE</code> printed to the terminal if the table was created successfully.</p>
<p>Now let's connect the two tables by adding a Foreign Key to books. Foreign Keys are unique identifiers that reference the Primary Key of another table. Books can, of course, have multiple authors but we’re not going to get into the complexities of many to many relationships right now.</p>
<p>Add a Foreign Key to <code>books</code> with the following command:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> books <span class="hljs-keyword">ADD</span> <span class="hljs-keyword">COLUMN</span> author_id <span class="hljs-built_in">INT</span> <span class="hljs-keyword">REFERENCES</span> <span class="hljs-keyword">authors</span>(author_id);
</code></pre>
<p>Next, let’s insert some sample data into the tables. We’ll start with <code>authors</code>.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">authors</span> (first_name, last_name) 
<span class="hljs-keyword">VALUES</span> (‘Tamsyn’, ‘Muir’), (‘Ann’, ‘Leckie’), (‘Zen’, ‘Cho’);
</code></pre>
<p>Select everything from <code>authors</code> to make sure the insert command worked.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">authors</span>;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-13.png" alt="Querying all data from the authors table" width="600" height="400" loading="lazy"></p>
<p><em>Querying all data from the authors table</em></p>
<p>Next, we’ll insert some books data into <code>books</code>.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> books(title, published_year, author_id) 
<span class="hljs-keyword">VALUES</span> (‘Gideon the Ninth’, <span class="hljs-number">2019</span>, <span class="hljs-number">1</span>), (‘<span class="hljs-keyword">Ancillary</span> Justice’, <span class="hljs-number">2013</span>, <span class="hljs-number">2</span>), (‘Black Water Sister’, <span class="hljs-number">2021</span>, <span class="hljs-number">3</span>);
</code></pre>
<p>If you run <code>SELECT * FROM books;</code> you’ll see the book data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-14.png" alt="Querying all data from the books table" width="600" height="400" loading="lazy"></p>
<p><em>Querying all data from the books table</em></p>
<h2 id="heading-how-to-list-all-tables">How to List All Tables</h2>
<p>You can use the <code>\dt</code> command to list all the tables in a database.</p>
<pre><code class="lang-python">\dt
</code></pre>
<p>For <code>books_db</code> you will see <code>books</code> and <code>authors</code>. You'll also see <code>books_book_id_seq</code> and <code>authors_author_id_seq</code>. These keep track of the sequence of integers used as ids by the tables because we used <code>SERIAL</code> to generate their Primary Keys.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-15.png" alt="Listing all tables in a database" width="600" height="400" loading="lazy"></p>
<p><em>Listing all tables in a database</em></p>
<h2 id="heading-how-to-describe-a-table">How to Describe a Table</h2>
<p>To see more information about a particular table, you can use the describe table command: <code>\d table_name</code>. This will list the columns, indexes, and any references to other tables.</p>
<pre><code class="lang-python">\d table_name
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-25.png" alt="Describing the authors table" width="600" height="400" loading="lazy"></p>
<p><em>Describing the authors table</em></p>
<p>Using <code>\dt+ table_name</code> will provide more information, such as about storage and compression.</p>
<h2 id="heading-how-to-rename-a-table">How to Rename a Table</h2>
<p>If you ever need to change the name of a table, you can rename it with the <code>ALTER TABLE</code> command.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> table_name <span class="hljs-keyword">RENAME</span> <span class="hljs-keyword">TO</span> new_table_name;
</code></pre>
<h2 id="heading-how-to-delete-a-table">How to Delete a Table</h2>
<p>If you want to delete a table, you can use the <code>DROP TABLE</code> command.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> table_name;
</code></pre>
<p>If you try to delete a table that doesn’t exist, you will get an error. You can avoid this by including the <code>IF EXISTS</code> option in the statement. This way you’ll get a notice instead.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> table_name;
</code></pre>
<h2 id="heading-how-to-manage-longer-commands-and-queries">How to Manage Longer Commands and Queries</h2>
<p>If you’re writing longer SQL queries, the command line isn’t the most ergonomic way to do it. It's probably better to write your SQL in a file and then have psql execute it.</p>
<p>If you are working with psql and think your next query will be long, you can open a text editor from psql and write it there. If you have an existing query, or maybe want to run several queries to load sample data, you can execute commands from a file that is already written.</p>
<h3 id="heading-option-1-open-a-text-editor-from-psql">Option 1 – Open a text editor from psql</h3>
<p>If you enter the <code>\e</code> command, psql will open a text editor. When you save and close the editor, psql will run the command you just wrote.</p>
<pre><code class="lang-python">\e
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-30.png" alt="Writing commands in a text editor" width="600" height="400" loading="lazy"></p>
<p><em>Writing commands in a text editor</em></p>
<p>On Windows, the default text editor for psql is Notepad, while on MacOs and Linux it's vi. You can change this to another editor by setting the <code>EDITOR</code> value in your computer’s environment variables.</p>
<h3 id="heading-option-2-execute-commands-and-queries-from-a-file">Option 2 – Execute commands and queries from a file</h3>
<p>If you have particularly long commands or multiple commands that you want to run, it would be better to write the SQL in a file ahead of time and have psql execute that file once you’re ready.</p>
<p>The <code>\i</code> command lets you read input from a file as if you had typed it into the terminal.</p>
<pre><code class="lang-python">\i path_to_file/file_name.sql
</code></pre>
<p><strong>Note:</strong> If you're executing this command on Windows, you still need to use forward slashes in the file path.</p>
<p>If you don’t specify a path, psql will look for the file in the last directory that you were in before you connected to PostgreSQL.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-29.png" alt="Executing SQL commands from a file" width="600" height="400" loading="lazy"></p>
<p><em>Executing SQL commands from a file</em></p>
<h2 id="heading-how-to-time-queries">How to Time Queries</h2>
<p>If you want to see how long your queries are taking, you can turn on query execution timing.</p>
<pre><code class="lang-python">\timing
</code></pre>
<p>This will display in milliseconds the time that the query took to complete.</p>
<p>If you run the <code>\timing</code> command again, it will turn off query execution timing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-19.png" alt="Using query execution timing" width="600" height="400" loading="lazy"></p>
<p><em>Using query execution timing</em></p>
<h2 id="heading-how-to-import-data-from-a-csv-file">How to Import Data from a CSV File</h2>
<p>If you have a CSV file with data and you want to load this into a PostgreSQL database, you can do this from the command line with psql.</p>
<p>First, create a CSV file called <code>films.csv</code> with the following structure (It doesn’t matter if you use Excel, Google Sheets, Numbers, or any other program).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-21.png" alt="A spreadsheet with Pixar film data" width="600" height="400" loading="lazy"></p>
<p><em>A spreadsheet with Pixar film data</em></p>
<p>Open psql and create a <code>films_db</code> database, connect to it, and create a <code>films</code> table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">DATABASE</span> films_db;

\c films_db

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> films(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    title <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>),
    <span class="hljs-keyword">year</span> <span class="hljs-built_in">INT</span>,
    running_time <span class="hljs-built_in">INT</span>
);
</code></pre>
<p>You can then use the <code>\copy</code> command to import the CSV file into <code>films</code>. You need to provide an absolute path to where the CSV file is on your computer.</p>
<pre><code class="lang-python">\copy films(title, year, running_time) FROM <span class="hljs-string">'path_to_file'</span> DELIMITER ‘,’ CSV HEADER;
</code></pre>
<p>The <code>DELIMITER</code> option specifies the character that separates the columns in each row of the file being imported, <code>CSV</code> specifies that it is a CSV file, and <code>HEADER</code> specifies that the file contains a header line with the names of the columns.</p>
<p><strong>Note:</strong> The column names of the <code>films</code> table don't need to match the column names of <code>films.csv</code> but they do need to be in the same order.</p>
<p>Use <code>SELECT * FROM films;</code> to see if the process was successful.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-31.png" alt="Importing data from a .csv file." width="600" height="400" loading="lazy"></p>
<p><em>Importing data from a .csv file</em></p>
<h2 id="heading-how-to-back-up-a-database-with-pgdump">How to Back Up a Database with <code>pg_dump</code></h2>
<p>If you need to backup a database, <code>pg_dump</code> is a utility that lets you extract a database into a SQL script file or other type of archive file.</p>
<p>First, on the command line (not in psql), navigate to the PostgreSQL <code>bin</code> folder.</p>
<pre><code class="lang-python">cd <span class="hljs-string">"C:\Program Files\PostgreSQL\14\bin"</span>
</code></pre>
<p>Then run the following command, using <code>postgres</code> as the username, and filling in the database and output file that you want to use.</p>
<pre><code class="lang-python">pg_dump -U username database_name &gt; path_to_file/filename.sql
</code></pre>
<p>Use <code>postgres</code> for the username and you will be prompted for the <code>postgres</code> superuser's password. <code>pg_dump</code> will then create a <code>.sql</code> file containing the SQL commands needed to recreate the database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-60.png" alt="Backing up a database to a .sql file." width="600" height="400" loading="lazy"></p>
<p><em>Backing up a database to a .sql file</em></p>
<p>If you don’t specify a path for the output file, <code>pg_dump</code> will save the file in the last directory that you were in before you connected to PostgreSQL.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-45.png" alt="Contents of films.sql backup file" width="600" height="400" loading="lazy"></p>
<p><em>Contents of films.sql backup file</em></p>
<p>You can pass the <code>-v</code> or <code>--verbose</code> flag to <code>pg_dump</code> to see what <code>pg_dump</code> is doing at each step.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-61.png" alt="Running pg_dump in verbose mode." width="600" height="400" loading="lazy"></p>
<p><em>Running pg_dump in verbose mode</em></p>
<p>You can also backup a database to other file formats, such as <code>.tar</code> (an archive format).</p>
<pre><code class="lang-python">pg_dump -U username -F t database_name &gt; path_to_file/filename.tar
</code></pre>
<p>Here the <code>-F</code> flag tells <code>pg_dump</code> that you're going to specify an output format, while <code>t</code> tells it it's going to be in the <code>.tar</code> format.</p>
<h2 id="heading-how-to-restore-a-database">How to Restore a Database</h2>
<p>You can restore a database from a backup file using either psql or the <code>pg_restore</code> utility. Which one you choose depends on the type of file you are restoring the database from.</p>
<ol>
<li><p>If you backed up the database to a plaintext format, such as <code>.sql</code>, use psql.</p>
</li>
<li><p>If you backed up the database to an archive format, such as <code>.tar</code>, use <code>pg_restore</code>.</p>
</li>
</ol>
<h3 id="heading-option-1-restore-a-database-using-psql">Option 1 – Restore a database using psql</h3>
<p>To restore a database from a <code>.sql</code> file, on the command line (so not in psql), use <code>psql -U username -d database_name -f filename.sql</code>.</p>
<p>You can use the <code>films_db</code> database and <code>films.sql</code> file you used earlier, or create a new backup file.</p>
<p>Create an empty database for the file to restore the data into. If you're using <code>films.sql</code> to restore <code>films_db</code>, the easiest thing might be to delete <code>films_db</code> and recreate it.</p>
<pre><code class="lang-python">DROP DATABASE films_db;

CREATE DATABASE films_db;
</code></pre>
<p>In a separate terminal (not in psql), run the following command, passing in <code>postgres</code> as the username, and the names of the database and backup file you are using.</p>
<pre><code class="lang-python">psql -U username -d database_name -f path_to_file/filename.sql
</code></pre>
<p>The <code>-d</code> flag points psql to a specific database, while the <code>-f</code> flag tells psql to read from the specified file.</p>
<p>If you don’t specify a path for the backup file, psql will look for the file in the last directory that you were in before you connected to PostgreSQL.</p>
<p>You will be prompted for the <code>postgres</code> superuser's password and then will see a series of commands get printed to the command line while psql recreates the database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-52.png" alt="Restoring a database using psql." width="600" height="400" loading="lazy"></p>
<p><em>Restoring a database using psql</em></p>
<p>This command ignores any errors that occur during the restore. If you want to stop restoring the database if an error occurs, pass in <code>--set ON_ERROR_STOP=on</code>.</p>
<pre><code class="lang-python">psql -U username -d database_name --set ON_ERROR_STOP=on -f filename.sql
</code></pre>
<h3 id="heading-option-2-restore-a-database-using-pgrestore">Option 2 – Restore a database using <code>pg_restore</code></h3>
<p>To restore a database using <code>pg_restore</code>, use <code>pg_restore -U username -d database_name path_to_file/filename.tar</code>.</p>
<p>Create an empty database for the file to restore the data into. If you're restoring <code>films_db</code> from a <code>films.tar</code> file, the easiest thing might be to delete <code>films_db</code> and recreate it.</p>
<pre><code class="lang-python">DROP DATABASE films_db;

CREATE DATABASE films_db;
</code></pre>
<p>On the command line (not in psql), run the following command, passing in <code>postgres</code> as the username, and the names of the database and backup file you are using.</p>
<pre><code class="lang-python">pg_restore -U username -d database_name path_to_file/filename.tar
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-54.png" alt="Restoring a database using pg_restore" width="600" height="400" loading="lazy"></p>
<p><em>Restoring a database using pg_restore</em></p>
<p>You can also pass in the <code>-v</code> or <code>--verbose</code> flag to see what <code>pg_restore</code> is doing at each step.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/image-55.png" alt="Using pg_restore in verbose mode" width="600" height="400" loading="lazy"></p>
<p><em>Using pg_restore in verbose mode</em></p>
<h2 id="heading-how-to-quit-psql">How to Quit psql</h2>
<p>If you’ve finished with psql and want to exit from it, enter <code>quit</code> or <code>\q</code>.</p>
<pre><code class="lang-python">\q
</code></pre>
<p>This will close the psql application if you were using it, or return you to your regular command prompt if you were using psql from the command line.</p>
<h2 id="heading-where-to-take-it-from-here">Where to Take it from Here</h2>
<p>There are lots more things you can do with psql, such as managing schemas, roles, and tablespaces. But this guide should be enough to get you started with managing PostgreSQL databases from the command line.</p>
<p>If you want to learn more about PostgreSQL and psql, you could try out freeCodeCamp’s <a target="_blank" href="https://www.freecodecamp.org/learn/relational-database/">Relational Database Certificate</a> . The official <a target="_blank" href="https://www.postgresql.org/docs/current/">PostgreSQL documentation</a> is comprehensive, and <a target="_blank" href="https://www.postgresqltutorial.com/postgresql-administration/psql-commands/">PostgreSQL Tutorial</a> offers several in-depth tutorials.</p>
<p>I hope you find this guide helpful as you continue to learn about PostgreSQL and relational databases.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
