Skip to content

Building SEO-Powered Websites With Gatsby

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Gatsby is a framework that leverages React for building SEO-powered websites. Many websites are created to be discovered, hence, SEO support is an important factor in such websites.

Many factors influence SEO such as accessibility, correct meta-information (at the head tag) and some other external tools. Gatsby supports using appropriate meta information for individual pages to improve their presence online.

In this article, we'll look at the limitations of Create React App in respect to SEO, and how Gatsby solves this with SSR. Furthermore in the article, we'll go through a tutorial on building a basic website with good SEO.

Why CRA is not a good tool for SEO

CRA is an opinionated tool used for building React applications but cannot be used for SEO. Here's why:

When using React, you'll most probably be using a library like react-helmet (a document head manager for React) for updating meta-information about the site. The limitations of such libraries is that they contain JavaScript, which means they can only be executed on the browser (so JavaScript can run).

SEO crawlers or social media tools that inspect head tags of websites (to display a card, perhaps) would not execute that JavaScript. Instead, they make use of the default meta information they can find. In CRA, the default title in public/index.html is "React App". This means, for every page you create (based on routes), they will all have the same title. They only show different titles when they are executed on the client's browser because the react-helmet library gets the chance to be executed, thereby updating the head tags. This article contains more information.

How Gatsby solves React SEO problems with SSR

Gatsby is a Static Site Generator (SSG) which uses Server Side Rendering (SSR) to generate static pages during the build process.

What this means is that you provide dynamic meta information in every page, and during the process of static site generation, pages are server-side rendered with the specified meta information, thereby making static pages with their own details.

With this technique, every page contains its own meta title, meta description and basically every meta information.

The following tutorial shows how Gatsby improves SEO in web applications.

Building an SEO powered site with Gatsby

We'll be building a basic website with two pages: / - Home and /about - About Us. These two pages would have their own meta information attached to them during the build process.

To get started, let's created our Gatsby project. Run the following in your terminal:

gatsby new new-project https://github.com/gatsbyjs/gatsby-starter-default

This pulls the default template, and installs all necessary dependencies. In the src directory, you'll find three directories: components, images and pages.

As you may observe, the template already comes with some configurations for seo and optimizing images. To build our project afresh, delete the following files/directories:

components/header.js
components/layout.css
components/layout.js
components/image.js
pages/404.js
pages/page-2.js
pages/index.js
pages/using-typescript.tsx

This will leave us with components/seo.js and images.

In a future series, we'll explore the gatsby-image plugin used in components/images.js. But for now, understand that it performs optimizations on images.

Let's briefly explore the content of components/seo.js

function SEO({ description, lang, meta, title }) {
	const { site } = useStaticQuery(
		graphql`
			query {
				site {
					siteMetadata {
						title
						description
						author
					}
				}
			}
		`
	);

	const metaDescription = description || site.siteMetadata.description;
	const defaultTitle = site.siteMetadata?.title;

	return (
		<Helmet
			htmlAttributes={{
				lang,
			}}
			title={title}
			titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}
			meta={[
				{
					name: `description`,
					content: metaDescription,
				},
				{
					property: `og:title`,
					content: title,
				},
				{
					property: `og:description`,
					content: metaDescription,
				},
				{
					property: `og:type`,
					content: `website`,
				},
				{
					name: `twitter:card`,
					content: `summary`,
				},
				{
					name: `twitter:creator`,
					content: site.siteMetadata?.author || ``,
				},
				{
					name: `twitter:title`,
					content: title,
				},
				{
					name: `twitter:description`,
					content: metaDescription,
				},
			].concat(meta)}
		/>
	);
}

SEO.defaultProps = {
	lang: `en`,
	meta: [],
	description: ``,
};

SEO.propTypes = {
	description: PropTypes.string,
	lang: PropTypes.string,
	meta: PropTypes.arrayOf(PropTypes.object),
	title: PropTypes.string.isRequired,
};

Note that this component can look a bit different in another template, or you may do it differently.

The SEO component receives four props: title, description, lang and meta with title as required. You can specify more props if you want or take out those you don't need.

This allows different pages to specify their titles, descriptions and other meta information specific to them.

Helmet is from react-helmet but is used a bit different from how it is used in CRA. It works with gatsby-plugin-react-helmet which provides server rendering support.

components/seo.js also contains some GraphQL which we will cover in a future series.

The Helmet plugin during the build process populates all pages with their respective meta information depending on the inputs provided during development.

Now let's add our pages.

With Gatsby, you do not need any routing packages for determining components to show based on specific URLs. To create a page, all you need to do is add the component's file directly under the pages directory.

To create the two pages for our project, add two files: index.js for / and about.js for /about.

Before proceeding with our pages, let's add a layout.

Create components/layout.js and components/header.js.

Add the following in components/header.js:

import { Link } from "gatsby";
import React from "react";
import PropTypes from "prop-types";

const Header = ({ siteName }) => {
	return (
		<header className="header">
			<div className="site">
				<Link to="/">{siteName}</Link>
			</div>
			<nav>
				<ul>
					<li>
						<Link to="/">Home</Link>{" "}
					</li>
					<li>
						<Link to="/about">About</Link>{" "}
					</li>
				</ul>
			</nav>
		</header>
	);
};

Header.propTypes = {
	siteName: PropTypes.string.isRequired,
};

export default Header;

Same React. The only thing new here is a different Link component from Gatsby is used.

In the components/layout.js, add the following:

import React from "react";
import Header from "./header";

const Layout = ({ children }) => {
	return (
		<div>
			<Header siteName="My Project" />
			{children}
		</div>
	);
};

export default Layout;

For the pages, add the following to index.js:

import React from "react";
import { Link } from "gatsby";

import Layout from "../components/layout";
import SEO from "../components/seo";

const IndexPage = () => (
	<Layout>
		<SEO title="Homepage" description="This is the homepage of my website" />
		<div className="hero-container">
			<div className="hero-left">
				<span className="hero-left-heading">Buy your Laptops Here</span>
				<span className="hero-left-text">
					You can get quality laptops here. What are you waiting for to make
					your first purchase?
				</span>
				<Link className="hero-left-link" to="/about">
					Learn More about me
				</Link>
			</div>
			<div className="hero-right">
				<div className="hero-right-image-container">
					<img src={require("../images/laptop.jpg")} />
				</div>
			</div>
		</div>
	</Layout>
);

export default IndexPage;

I added an unsplash image to images and required it require('../images/laptop.jpg') as seen above.

We'll look at the usage of the SEO component soon.

For pages/about.js, add the following:

import React from "react";

import Layout from "../components/layout";
import SEO from "../components/seo";

const AboutPage = () => (
	<Layout>
		<SEO
			title="About my website"
			description="This page contains more information about my website and the work that I do"
		/>
		<main>
			<div className="about-container">
				<h1>About Me</h1>
				<p>I sell quality computers!! Okay?</p>
			</div>
		</main>
	</Layout>
);

export default AboutPage;

Create a new directory called styles under src and create a new file: global.css. Copy the following css styles to that file:

* {
	box-sizing: border-box;
}

body {
	margin: 0;
	padding: 0;
}

ul {
	padding: 0;
	list-style: none;
}

.header {
	padding: 20px;
	background-color: rgb(5, 42, 123);
	display: flex;
	justify-content: space-between;
	align-items: center;
}

.header .site a {
	color: white;
	font-size: 30px;
	text-decoration: none;
}

.header nav ul {
	display: flex;
}
.header nav ul li a {
	color: white;
	margin: 20px;
}

.hero-container {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 100px 30px;
}

.hero-left {
	display: flex;
	flex-direction: column;
	max-width: 500px;
	padding: 20px;
}

.hero-left-heading {
	font-size: 40px;
	color: rgb(181, 0, 154);
	font-weight: bold;
}

.hero-left-text {
	margin: 20px 0;
}

.hero-left-link {
	display: block;
	width: max-content;
	padding: 15px;
	border-radius: 5px;
	background-color: rgb(181, 0, 154);
	color: white;
	display: flex;
	justify-content: center;
	align-items: center;
	text-decoration: none;
}

.hero-right-image-container {
	width: 600px;
	height: 400px;
	overflow: hidden;
}
.hero-right-image-container img {
	object-fit: cover;
	width: 100%;
	height: 100%;
}

.about-container {
	margin-top: 100px;
	text-align: center;
}

.about-container h1 {
	font-size: 50px;
}

For the global stylesheet to be used for the whole site, the gatsby-browser.js API file would be used.

gatsby-browser.js is a reserved API file that gives access to actions within the browser.

In gatsby-browser.js (at the root of your project), add the following:

import "./src/styles/global.css";

When you run the gatsby server for your project (gatsby develop), you'll get the following on localhost:8000:

For /:

Gatsby Basic Website Homepage

For /about:

Gatsby Basic Website About page

The SEO component makes all the pages unique and SEO-ready. For index.js, we have:

<SEO title="Homepage" description="This is the homepage of my website" />

Just as we have configured the SEO component using react-helmet, this updates the meta information for the homepage during the build process. This way, the first thing crawlers will see is the unique meta details for the page, as they do not require any JavaScript to be updated.

To test this, do the following:

  • build for project for production (gatsby run build)
  • serve the production build (gatsby run serve)

This will run the built content on localhost:9000.

You can use curl on your terminal to inspect the source code (or run inspect on the browser).

curl localhost:9000

The result:

Gatsby Basic Website Homepage Source

The reason it came out as "Homepage | Gatsby Default Starter" is because of the prop titleTemplate provided by Helmet which was configured like so in the SEO template:

titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}

This appends a default title to every title provided by the pages.

Conclusion

In this article, we looked at how Gatsby solves the problem of SEO using server side rendering for generating static pages.

The basic example used in the tutorial shows how each page contain their own meta information that can easily be crawled by SEO bots or social media tools.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

How to test React custom hooks and components with Vitest cover image

How to test React custom hooks and components with Vitest

Introduction In this guide, we'll navigate through the process of testing React hooks and components using Vitest—a powerful JavaScript unit testing framework. Discover how Vitest simplifies testing setups, providing an optimal solution for both Vite-powered projects and beyond. Vitest is a javascript unit testing framework that aims to position itself as the Test Runner of choice for Vite projects and as a solid alternative even for projects not using Vite. Vitest was built primarily for Vite-powered projects, to help reduce the complexity of setting up testing with other testing frameworks like Jest. Vitest uses the same configuration of your App (through vite.config.js), sharing a common transformation pipeline during dev, build, and test time. Prerequisites This article assumes a solid understanding of React and frontend unit testing. Familiarity with tools like React Testing Library and JSDOM will enhance your grasp of the testing process with Vitest. Installation and configuration Let’s see how we can use Vitest for testing React custom hooks and components. But first, we will need to create a new project with Vite! If you already have an existing project, you can skip this step. ` Follow the prompts to create a new React project successfully. For testing, we need the following dependencies installed: Vitest as the unit testing framework JSDOM as the DOM environment for running our tests React Testing Library as the React testing utilities. To do so, we run the following command: ` Once we have those packages installed, we need to configure the vite.config.js file to run tests. By default, some of the extra configs we need to set up Vitest are not available in the Vite config types, so we will need the vite.config.ts file to reference Vitest types by adding /// reference types=”vitest” /> at the top of the file. Add the following code to the vite.config.ts ` We set globals to true because, by default, Vitest does not provide global APIs for explicitness. So with this set to true, we can use keywords like describe, test and it without needing to import them. To get TypeScript working with the global APIs, add vitest/globals to the types field in your tsconfig.json. ` The environment property tells Vitest which environment to run the test. We are using jsdom as the environment. The root property tells Vitest the root folder from where it should start looking for test files. We should add a script for running the test in package.json ` With all that configured, we can now start writing unit tests for customs hooks and React components. Writing test for custom hooks Let’s write a test for a simple useCounter hook that takes an initial value and returns the value, an increment function and a decrement function. ` We can write a test to check the default return values of the hook for value as below: ` To test if the hook works when we increment the value, we can use the act() method from @testing-library/react to simulate the increment function, as shown in the below test case: ` Kindly Note that you can't destructure the reactive properties of the result.current instance, or they will lose their reactivity. Testing hooks with asynchronous logic Now let’s test a more complex logic that contains asynchronous logic. Let’s write a useProducts hook that fetches data from an external api and return that value ` Now, let’s see what the test looks like: ` In the above example, we had to spy on the global fetch API, so that we can mock its return value. We wrapped that inside a beforeAll so that this runs before any test in this file. Then we added an afterAll method and called the mockRestore() to run after all test cases have been completed and return all mock implementations to their original function. We can also use the mockClear() method to clear all the mock's information, such as the number of calls and the mock's results. This method is handy when mocking the same function with different return values for different tests. We usually use mockClear() in beforeEach() or afterEach() methods to ensure our test is isolated completely. Then in our test case, we used a waitFor(), to wait for the return value to be resolved. Writing test for components Like Jest, Vitest provides assertion methods (matchers) to use with the expect methods for asserting values, but to test DOM elements easily, we will need to make use of custom matchers such as toBeInTheDocument() or toHaveTextContent(). Luckily the Vitest API is mostly compatible with the Jest API, making it possible to reuse many tools originally built for Jest. For such methods, we can install the @testing-library/jest-dom package and extend the expect method from Vitest to include the assertion methods in matchers from this package. ` After installing the jest-dom testing library package, create a file named vitest-setup.ts on the root of the project and import the following into the project to extend js-dom custom matchers: ` Since we are using typescript, we also need to include our setup file in our tsconfig.json: ` In vite.config.ts, we need to add the vitest-setup.ts file to the test.setupFiles field: ` Now let’s test the Products.tsx component: ` We start by spying and mocking the useProducts hook with vi.spyOn() method from Vitest: ` Now, we render the Products component using the render method from @testing-library/react and assert that the component renders the list of products as expected and also the product has the title as follows: ` In the above code, we use the render method from @testing-library/react to render the component and this returns some useful methods we can use to extract information from the component like getByTestId and getByText. The getByTestId method will retrieve the element whose data-testid attribute value equals product-list, and we can then assert its children to equal the length of our mocked items array. Using data-testid attribute values is a good practice for identifying a DOM element for testing purposes and avoiding affecting the component's implementation in production and tests. We also used the getByText method to find a text in the rendered component. We were able to call the toBeInTheDocument() because we extended the matchers to work with Vitest earlier. Here is what the full test looks like: ` Conclusion In this article, we delved into the world of testing React hooks and components using Vitest, a versatile JavaScript unit testing framework. We walked through the installation and configuration process, ensuring compatibility with React, JSDOM, and React Testing Library. The comprehensive guide covered writing tests for custom hooks, including handling asynchronous logic, and testing React components, leveraging custom matchers for DOM assertions. By adopting Vitest, developers can streamline the testing process for their React applications, whether powered by Vite or not. The framework's seamless integration with Vite projects simplifies the setup, reducing the complexities associated with other testing tools like Jest....

Improving INP in React and Next.js cover image

Improving INP in React and Next.js

Improving INP in React and Next.js In one of my previous articles, I've explained what INP is, how it works, and how it may affect your website. I also promised you to follow up with more concrete advice on how to improve your INP in your favorite framework. This is the follow-up article, where I'll focus on how to improve your INP score in React and Next.js. How to prepare for INP in React and Next.js? The first thing to do is to ensure you're using the latest version of React. The React team has been working on making React more INP-friendly and has already made some improvements in the latest versions. To enhance your INP score, consider fully taking advantage of new features introduced in React 18, such as Concurrent Rendering, Automatic Batching, and Selective Hydration. However, there are also some general areas to focus on, such as SSR and SSG in Next.js, Web Workers, or optimizing your hooks and state management. Concurrent Rendering The Concurrent Mode in React uses an algorithm that breaks rendering down into so-called "fiber nodes" and schedules the renders based on their expiration and priority. This effectively allows the user to interact with the page while the rendering is still in progress. In previous React versions, all updates, such as setState calls were treated as "urgent" and once the re-render had started, there was no way to interrupt it. Concurrent Mode changes this by being able to prioritize the updates and interrupt a non-blocking state update started with startTransition. For a simple explanation of concurrency in React, you can check out Dan Abramov's explanation. As part of the Concurrent Mode, React introduced several lifecycle methods that allow you to prioritize the rendering of certain parts of your UI, such as: - useTransition hook that allows you to update the state without blocking the UI, - useDeferredValue hook that allows you to defer the rendering of certain parts of your UI, - startTransition API that, similarly to the useTransition hook lets you mark a state update as non-blocking. It lacks, however, an indication of whether it's still pending. Automatic Batching Introduced in React 18, Automatic Batching reduces the number of re-renders that happen on state changes even when they happen outside of event handlers, e.g. in a setTimeout or Promise callback. This feature comes out of the box and you don't have to do anything to enable it, and it makes a great argument for upgrading to React 18. Selective Hydration Selective Hydration allows you to take hydration off the main thread by wrapping your components in a Suspense boundary. This way, components can become interactive faster as the browser can do other work on the main thread while the hydration is happening. To fully take advantage of selective hydration, consider the following: - Prioritizing Above-the-Fold Content: Use Suspense boundaries strategically around any parts of your application that may take the server longer to deliver to ensure they don’t block critical content from becoming interactive as soon as possible. - Hydration on Interaction: Implementing hydration upon user interaction for non-critical components can drastically reduce the main thread's workload, enhancing INP. Vercel even has a small case study showing how using selective hydration improved the performance of a Next.js site. Server-Side Rendering (SSR) and Static Site Generation (SSG) in Next.js Not everything has to run client-side. Next.js excels in SSR and SSG capabilities, which can significantly impact INP by delivering content to users faster. Optimizing SSR with techniques like incremental static regeneration (ISR) or leveraging SSG for static pages ensures that users can interact with content faster, improving the perceived performance. Workers Offloading heavy computations to Web Workers can free up the main thread, enhancing the responsiveness of React and Next.js applications. This strategy is especially useful when dealing with third-party scripts. Offloading such scripts in Next.js can be easily done by specifying the "worker" strategy on your Script component. Be aware that this feature is not yet stable and does not work with the app directory, though. If you want to take things one step further, you could use Partytown, which helps you offload any resource-intensive scripts to Web Workers. It comes with a React component that you can use to wrap your third-party scripts and offload them to a Web Worker, and it's compatible with Next.js as well. Hooks and State Management State management in React applications can easily get out of hand, leading to unnecessary re-renders and effectively an increased INP. Sometimes, using a state management library like Redux or MobX can help you consolidate your state and reduce the number of re-renders. However, they are not silver bullets and can also introduce performance issues if not used properly. If you are dealing with a lot of re-renders due to prop changes, make sure you are leveraging memoization. As of now, you may need to work with useMemo and useCallback hooks to memoize your values and functions, respectively. The upcoming React 19’s Forget Compiler, however, will apparently memoize everything under the hood, making these hooks obsolete. Using memoization properly can help you reduce the number of re-renders and improve your INP. To investigate your hook dependencies and re-renders, you can leverage React Developer Tools or use this handy helper hook I found on the internet to trace your re-renders: ` Conclusion Improving INP in React and Next.js is not easy and can require much investigation and fine-tuning. Still, it's worth doing to avoid being penalized by Google in its search results and provide a better experience for your users. Adopting React 18's new features, leveraging SSR and SSG in Next.js, utilizing Web Workers, and optimizing hooks and state management can significantly boost your INP score and deliver a faster application to your users. Remember, INP is just one among many performance metrics emphasizing the need for a comprehensive approach to performance optimization...

Getting Started with GatsbyJS cover image

Getting Started with GatsbyJS

GatsbyJS is a React framework and a Static Site Generator (SSG) tool used in building web applications. It combines Server Side Rendering (SSR) features, and static site development for building SEO-powered, secured, and fast applications. In this article we’ll start with an introduction to Gatsby, we’ll learn the terms SSG, CSR, and SSR, how Gatsby improves SEO, and then we’ll build a simple website with Gatsby. Introduction GatsbyJS is built on React. React is a frontend UI library for frontend implementations. It supports the idea of small components that merges with other components to make bigger components. As a UI library, React is a tool that can be combined with other tools for building web applications. Therefore, React on its own may require other tools (like routing tools, webpack server, and so on) for building full-fledged frontend applications. With that being said, when you install React, you need to install other tools to make up your application. This results in an opinionated setup aided by Create React App (CRA). Despite this, more configurations and tools needed to be installed for a full application. Then, Gatsby! Gatsby is an opinionated framework that takes away the hassle of setting up the application and allows you to begin development immediately. Asides from this, Gatsby also solves the issue of Search Engine Optimisation (SEO) that using only React provides. react-helmet is not an effective SEO solution. This article explains that further. SSR, CSR, and SSG Client-Side Rendering (CSR) In CSR, all routings and renderings are handled by the browser with JavaScript. For this technique, different HTML files are not created for different pages, instead, one page referencing some JavaScript files that determine what to display depending on the URL. React is a CSR tool. This means all routings are handled by the browser. In React, you have an index.html file found in the public folder which codes similar to this: ` After the build process (npm run build), the index.html will look like this: ` The referenced .js files handles all routings and responds to the URL with contents to share. build/index.html is only fetched once, also with the JavaScript files. This may result in low page load speed due to fetching all resources. This method affects SEO in such a way that SEO crawlers only see React App and does not see every other meta changes because those changes only happen when libraries like react-helmet are executed (which is only on the browser). Server Side Rendering In contrast to CSR, SSR involves populating the browser with resources from the server. This means that for every route change, a request is made to the server to fetch new resources. SSR is perfect for SEO because SEO crawlers get the right meta information when any page is requested. SSR also has its cons, one of which is a delay when navigating between pages. CSR wins in this area because all JavaScript resources are fetched on the first request and every other navigation does not need a page refresh. Static Site Generator An SSG is a tool or set of tools that create static HTML pages from input files or content sources. Many SSG tools work in various ways but most of them take away the issues of security and slow fetching that database-driven platforms use. SSG takes content from different sources and builds them all into static pages which can be accessed faster when fetched by a browser. How Gatsby improves SEO Gatsby is an SSG tool that solves the issue of SEO that CSR brings and also makes routing faster compared to SSR. Gatsby does this by pre-building the web application before it is hosted. During the build process, all meta information provided within components is attached to the built pages. So when SEO crawlers or social sharing tools access any page of the application, they get access to the meta-information that has been provided to all pages during development. This does not involve any rendering in the browser. The built files are static pages which looks like each page was built separately like so: ` Building a simple website with Gatsby To show how Gatsby sites are built, we’ll be building a very simple website. No much complexities or dynamics, just simple. Install the CLI tool Firstly, install the gatsby CLI tool. Or you can use npx if that’s what you want. ` Create new site You can either create a new Gatsby site with a basic template ([gatsby-starter-default]9https://www.gatsbyjs.com/starters/gatsbyjs/gatsby-starter-default/)) provided by the team, or use a specify another template to customize. For the default template, a new site is created like so: ` Where new-site is the name of the project you’re creating. This gives the following project structure: The template provides SEO configurations using GraphQL which you can improve. To see the site in action, run: ` At localhost:8000, you’ll find your site displayed like so: Alternatively, you can specify a template you want to use. You can find different starter templates from their list of starter libraries. To use a template, say, gatsby-starter-blog, the following command will be used: ` This gives the following project structure: On starting the development server, localhost:8000 shows this: Improving the gatsby-starter-default template The template has three folders under src namely components, images and pages. The components and images page are optional, but pages is a required page for Gatsby. Unlike React, where you need a router library to show a set of components for a particular URL, in Gatsby, you create pages by having React JavaScript files under the pages folder. Let’s add an about page under pages like so: In about.js, you can create your React components or import components. For example: ` SEO is a component that dynamically updates meta information about each pages and Layout is a wrapper component that serves as the layout of all pages. This can be configured to fit your needs too. When you start your development server, go to localhost:8000/about and you’ll find this: Note that: whatever you can do in React (components structuring, prop-types, and so on), you can do the same in Gatsby. Gatsby makes things easier allow you to focus on the important parts of your application and pre-building your site to make SEO-fit. Also, Gatsby makes your site fast and since they are static pages, they can be served from anywhere (like CDNs). Conclusion Gatsby goes beyond the general understanding of “static pages”. Gatsby can source content from Content Management Systems and build static pages for them. An example is gatsby-source-instagram. It sources content from Gatsby at every building process, source the latest content from Instagram, and makes them available on your website. There a lot of other awesome applications that can be achieved by using Gatsby, such as e-commerce tools, portfolios, and so on. Here's a gallery of sites using Gatsby. Another beautiful thing about Gatsby is the community. You’ll find a ton of plugins that make development easier and more effective. This article gives introductory information on what makes Gatsby an awesome tool. There are still more to learn to make the best use of Gatsby such as Gatsby and GraphQL, SSR APIs, and many more. Their documentation gives a very great guide to learning more about the tool. I hope this article gives you reasons to try out Gatsby in your next project....

What does it actually look like to build software with AI today? Not in theory, but in practice. cover image

What does it actually look like to build software with AI today? Not in theory, but in practice.

What does it actually look like to build software with AI today? Not in theory, but in practice. At the Leadership Exchange, this was the question at the center of the Developer Panel, where leaders from across the industry unpacked what’s really changing inside engineering teams and what organizations need to do right now to keep up. The Developer Panel at the Leadership Exchange explored the cutting edge of AI in software engineering and examined what organizations should focus on today to prepare for the future. Moderated by Jeff Cross, Co-Founder & CEO at Nx, the panel featured Victor Savkin, Cofounder & CTO at Nx, Alex Sover, Vice President of Engineering at OpenAP, Brent Zucker, Senior Director of Engineering at Visa, and Jonathan Fontanez, AI Engineering Lead at This Dot Labs. Panelists shared insights into how AI is transforming the software development lifecycle and how teams can adopt tools effectively while preparing for organizational change. Panelists discussed emerging workflows, including CI-in-the-loop, agentic healing, and context engineering. They examined how validation, code reviews, and PRDs are evolving alongside AI capabilities and how teams are integrating external sources such as production traces to improve quality and reliability. The discussion also covered what the next generation of agentic tools might look like and how these capabilities will shape engineering practices in the near future. Adoption of AI comes with challenges. Teams often rely on plugins or extensions without foundational understanding, and individual contributors may fear displacement. Panelists emphasized that education, governance, and skill-building are essential for teams to manage AI agents effectively while maintaining quality. They also highlighted the need to standardize workflows and ensure organizational alignment to fully leverage AI capabilities. The conversation extended beyond technical challenges to organizational implications. Panelists discussed how teams can avoid issues like Conway’s Law, manage distributed teams effectively, and evolve engineering practices alongside AI adoption. Leadership and management strategies play a crucial role in ensuring that AI integration delivers meaningful outcomes while maintaining efficiency and alignment with business objectives. Key Takeaways - AI workflows require both technical and organizational preparation. - Education, governance, and skill development are essential for successful implementation. - Forward-looking teams are rethinking validation, CI pipelines, and context management to fully leverage agentic AI. The discussion highlighted that adopting AI at the cutting edge is not just about new tools - it is about rethinking processes, workflows, and organizational culture. Companies that embrace this holistic approach are most likely to succeed in leveraging AI to its full potential. Are you interested in more conversations like this? Message us for an invite to the next, or for a private discussion around these topics. Tracy can be reached at tlee@thisdot.co....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co