Editor’s Note: This post was updated on 1 December 2021 with new code blocks and relevant information.
Next.js and After.js are both frameworks that let us build server-side-rendered React apps without the hassle of setting up SSR from scratch from a create-react-app project. In this article, we’ll compare Next.js and After.js and explore their differences.
The major difference between Next.js and After.js is in the routing mechanism.
With Next.js, we don’t specify the routes directly; instead, we let Next.js deal with the routing automatically. It maps URLs to our components by checking the project’s file structure and mapping URLs directly to components with that.
With After.js, we need to specify the routes explicitly. After.js uses React Router to do the routing.
Most of the other features like data fetching and how pages are created are pretty much the same between the two. The way projects are created is done pretty much the same way with their own CLI programs, too.
The easiest way to create a Next.js project is to use create-next-app. To start, run:
npx create-next-app@latest # or yarn create next-app Note: For a Typescript project, add a ​​--typescript flag to this command.
To create an After.js project, we run:
yarn global add create-after-app // or npm install -g create-after-app create-after-app myapp
Note: At the time of writing, After.js throws an error with the latest version of React Router (see the GitHub issue here). A quick fix is to delete our node_modules
folder and update package.json
, like this:
"dependencies": { ... "react-router-dom": "^5.3.0" }
Once this is done, we can re-install the packages with yarn install
or npm install
.
Both Next.js and After.js let us create pages by adding React components. To illustrate, we’ll create an app using the News API with Next.js and After.js. All we have to do is create components, and then it’ll display in our app.
For the sake of fetching the data from the News API, we will be using the isomorphic-unfetch package. We can get it by running this command inside our newly created project:
npm i isomorphic-unfetch // or yarn add isomorphic-unfetch
We will also need an API key from the News API, which we can create for free.
In Next.js, if we create the page in the pages
folder, we can navigate to it via the URL with the same name.
For instance, in Next.js, we can create index.js
in the pages
folder, as follows:
import NavBar from '../components/navbar' import fetch from 'isomorphic-unfetch'; import HeadTag from '../components/head-tag'; export async function getStaticProps() { const res = await fetch(`https://newsapi.org/v2/top-headlines/?language=en&apiKey=${process.env.NEWS_API_KEY}`) const data = await res.json() return { props: { data, }, } } const Home = ({ data }) => ( <div> <HeadTag /> <NavBar /> {(data.articles) && data.articles.map(a => ( <div key={a.title}> <h1>{a.title}</h1> <p>{a.description}</p> <p>{a.content}</p> </div> ))} </div> ) export default Home
The getStaticProps
function will let us fetch data, and then we can get it from the props with the same name in our component.
We can create an about page in about.js
, as follows:
import NavBar from '../components/navbar' import HeadTag from '../components/head-tag' const Home = () => ( <div> <HeadTag /> <NavBar /> <p>This is a news app.</p> </div> ) export default Home
Now we can navigate directly to them by going to /
and /about
, respectively.
After creating the components
folder in our root project, we can create components that we can reference on the page by creating the following files:
//head-tag.js import Head from 'next/head' const HeadTag = () => ( <Head> <title>News App</title> </Head> ) export default HeadTag
//navbar.js import Link from 'next/link' const NavBar = () => ( <nav> <Link href="/"> <a>Home</a> </Link> <Link href="/about"> <a>About</a> </Link> </nav> ) export default NavBar
In our After.js app, we created the following components in the src
folder:
//Home.js import React, { Component } from 'react'; import NavBar from './NavBar'; import fetch from 'isomorphic-unfetch'; class Home extends Component { static async getInitialProps() { const res = await fetch(`https://newsapi.org/v2/top-headlines/?language=en&apiKey=${process.env.RAZZLE_APIKEY}`) const data = await res.json(); return { data }; } render() { const { data } = this.props; return ( <div> <NavBar /> {data.articles.map(a => ( <div key={a.title}> <h1>{a.title}</h1> <p>{a.description}</p> <p>{a.content}</p> </div> ))} </div> ); } } export default Home;
We get the data in the initialProps
static method, and then we can access it via the props.
//About.js import React, { Component } from 'react'; import NavBar from './NavBar'; class About extends Component { render() { return ( <div> <NavBar /> <p>This is a new app</p> </div> ); } } export default About;
The components that we reference in the pages can be created in the same folder:
// NavBar.js import React from 'react'; import { Link } from 'react-router-dom'; class NavBar extends React.Component { render() { return ( <div> <Link to="/">Home</Link> <Link to="/about">About</Link> </div> ); } } export default NavBar;
As we can see, these are all just standard components. The difference is that we used the Link
component from React Router for page navigation links in After.js, and in the Next.js project, we add page navigation with Next.js’ own Link
component.
All that being said, the experience for creating pages is pretty much the same in each framework.
Routing is where Next.js and After.js are quite different.
Next.js’ routing works out of the box without much hassle. Once we create the pages, we can navigate to them directly or with links rendered by the Link
component.
On the other hand, After.js is a lot trickier. If we have a page component that has the getInitialProps
method to fetch data, then we can’t add it to the routes file as an async component.
In our routes.js
file, which is in the src
folder of our After.js project, we have:
import React from 'react'; import { asyncComponent } from '@jaredpalmer/after'; import Home from './Home'; export default [ { path: '/', exact: true, component: Home, }, { path: '/about', exact: true, component: asyncComponent({ loader: () => import('./About'), // required Placeholder: () => <div>...LOADING...</div>, // this is optional, just returns null by default }), }, ];
About.js doesn’t fetch data before it renders, so we can include it as an async route. However, the Home
component can’t be included as an async route because we have the getInitialProps
async method to get data.
Routing is simply easier to deal with in a Next.js project. Routing is more configurable with After.js, but we’ve got to configure it ourselves.
Data fetching in both Next.js and After.js is done when the component is first rendered. As we can see from the previous section, index.js
in our Next.js project fetches data in the async getStaticProps
function.
In the After.js project, we use the getInitialProps
static method of the component class to fetch data before rendering the page.
In both components, the fetched data is available as props within the component.
In Next.js, built-in support has been added for environment variables. All we need is to create a .env.local file
in our root project and add:
NEWS_API_KEY=
Once saved, the file will automatically be loaded and the variables used in our application.
And, in the After.js project, environment variables are stored in the .env
file, and the keys for environment variables that we can use inside the project must be prefixed with RAZZLE_
.
For example, we can write it like this:
RAZZLE_APIKEY=your_api_key
In both frameworks, environment variables are available as a property of the process.env
object.
Both Next.js and After.js can be used to build server-side rendered projects. They’re useful for building server-side rendered apps without much effort.
The main difference between Next.js and After.js is the routing. Next.js maps URLs to components by their name and whether the component files are in the pages
folder. In contrast, After.js uses React Router for routing, and we’ve got to configure it ourselves.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
One Reply to "Comparing Next.js and After.js for SSR React apps"
The elephant in the room with Next.js is lack of nested routing[0]. In any moderately complex site, you don’t want to re-render all your components (header/footer) on a page transition. Which also requires you to include your React components on every route path (page.tsx). I was excited to migrate from a Vue.js SSR project to next.js/react, but these basic requirements seem to be lacking. After.js recognises this and uses React Router. But After.js does not have the momentum Next.js has.
Another issue with Next.js that I think stems from the lack of nested routing is the fact that routes with a getServerSideProps() are called even on client side page transitions[1]. This means that if you fetch data for the entire page, eg user, menu and footer data in getServerSideProps(), this will be fetched again and again on each and every page navigation. There are hacks for these issues, but After.js seems to not have these in the first place.
[0] https://github.com/vercel/next.js/issues/8193
[1] [https://github.com/vercel/next.js/issues/11897]