Deploying with Custom Serverless Next.js Routing
Migrate from a Next.js application with a custom server to a serverless Next.js application using Now routes.
Next.js offers developers a built-in routing system that allows you to link to other pages whilst also giving those pages a custom URL. When a user refreshes the custom URL, however, the browser will not be able to load the link because the page was previously routed client-side. To resolve this, we need to also handle routing server-side.
Preface: Next.js Routing
When you link to a page within the same Next.js application, you can provide two options. The first and required option is href
. This is a link to the page as it exists in the pages
directory. The second is as
which describes the URL Next.js should show when routing to that page.
For example, if you have a page located at pages/product.js
in your codebase, you can use the href
option with the value /product?name=<product_name>
to route and render that page with a query parameter, however, if you want to show the URL /product/<product_name>
, you can use the as
option to format the URL when routing.
This is an amazing feature of Next.js, however, it cannot control how the server routes to the application if the routes are not defined with the server.
The Old Custom Server Method
The solution to this problem was previously using a custom server. For example, you could create an Express application and catch the request to /product/<product_name>
and route it to the /product?name=<product_name>
file behind the scenes so that you can keep the custom URL:
server.get('/products/:name', (req, res) => { return app.render(req, res, '/product', { name: req.params.name }) })
An example custom server route capture and render method.
The New Routes Method
With Now 2.0 and the serverless approach, each Next.js page is a separate entry point, making the sole custom server entry point a thing of the past for the good of performance and stability. Fortunately, Now 2.0 offers a solution, by way of the routes
configuration.
The following now.json
configuration enables the deployment to use the Now platform version 2.0 and defines the routes that the deployment should acknowledge when receiving a request to an entry point.
{ "version": 2, "routes": [ { "src": "/product/(?<name>[^/]+)$", "dest": "/product?name=$name" } ] }
Using Now 2.0 routes configuration to rewrite URLs to the rendered Next.js page with an embedded capture group to route query parameters.
now.json
file does not include a builds option which is necessary for building a Next.js application with Now. Please see the Next.js Builder documentation for more information.By Example
If you are yet to set up routing for your Next.js app, this brief example describes how to use Next.js routing with Now routes
to support custom URLs.
Step 1: Defining Pages
The first part of creating defined routes is to make sure those routes can be rendered as pages. In this example, we will have two pages, "index" (our homepage) and "product".
The index.js
inside of our pages
directory is just a small page that exports a heading and a paragraph of text with a link to our future products page using a Next.js Link component:
import Link from 'next/link' export default () => ( <div> <h1>Welcome to our Next.js website!</h1> <p> View our{' '} <Link href="/product?name=espresso"> <a>espresso product</a> </Link> ! </p> </div> )
Next, for our link to work, we need to create a product.js
file in our pages
directory. This page displays the query parameter, which we receive with the Next.js getInitialProps
lifecycle method, as the title and a simple paragraph:
const Product = ({ name }) => ( <div> <h1>{name}</h1> <p>Welcome to our product page for {name}!</p> </div> ) Product.getInitialProps = async ({ query }) => { return { name: query.name } } export default Product
Step 2: Defining a Custom URL
With the pages set up, we can now define the product page to have a custom URL.
The first part of this is to extend the Link
component usage in the index page to contain an as
attribute that defines our custom URL. Taking the line consisting of a paragraph and a Next.js link in the index.js
file, we can add the as
attribute with a custom URL.
import Link from 'next/link' export default () => ( <div> <h1>Welcome to our Next.js website!</h1> - <p>View our <Link href="/product?name=espresso"><a>espresso product</a></Link>!</p> + <p>View our <Link href="/product?name=espresso" as="/product/espresso"><a>espresso product</a></Link>!</p> </div> )
A diff of the changes made to the index.js
page file.
Now, clicking the espresso product link will result in the URL path being /product/espresso
while rendering the product
page with the name query parameter set to espresso
.
Step 3: Defining routes
configuration
When refreshing the URL with the path of /product/espresso
, or accessing it directly, you will find that the server will return a 404 response. This is because there is no entry point that exists for that path. Next.js handles the routing to that page internally on the client-side. The next step is to provide Now with the context of this path to route to the /product
page entry point.
For this context, we can use the routes
configuration option inside of a now.json
file:
{ "version": 2, "routes": [ { "src": "/product/(?<name>[^/]+)$", "dest": "/product?name=$name" } ] }
An example now.json
configuration that rewrites our custom path to the product page with a query parameter.
builds
property which is necessary for Now to build and serve a Next.js application. Please see the Next.js Builder documentation for more information.The routes property, as exampled above, allows us to define a named capture group that gets the query parameter from the URL path and enables the usage of that parameter in the destination path by using the capture ID prefixed by a dollar sign, in our case: $name
.
Step 4: Deploying
With the Next.js application setup complete and Now configured to accept the custom routes, we can finally deploy our application using Now and the Next.js Builder.
If you are using Now for GitHub; pushing your code to your repository is all you need to do for Now to automatically deploy your application.
Once you deploy, you will receive a deployment URL, similar to the following which contains this example with a few styling tweaks for ease on the eyes: https://next-routes-2s2lop08x.now.sh/
The full source of the deployment is also available here: https://next-routes-2s2lop08x.now.sh/_src