Reputation: 149
I have a Next.js (pages) app, with many API routes in the /api
folder. I am hosting this on Vercel, where there is a 10 second execution limit.
I have some API routes that take a long time to process data, and I want to move these to a standalone serverfull Express.js application, so they can take as long as they need.
I'm wondering how I can have both the Express.js server and the Next.js application in a monorepo? And then how do I host the Next.js portion of the monorepo on Vercel, and the Express.js portion on Railway? I want to have shared types and interfaces between the Next.js app and the Express.js app (e.g., re-use some util functions in the express app).
Currently, I have a completely seperate Express.js server where I've essentially re-written many of the types, interfaces and functions that could otherwise be shared if it was in a mono-repo.
I have tried to use nx, but my issue is that I already have the Next.js application, and I'm not sure how to integrate that into a monorepo, and then generate an express application using the nx CLI.
Upvotes: 1
Views: 981
Reputation: 149
I eventually figured out how to achieve this, so I will share my answer:
To create a Next.js and Express monorepo, with shared packages:
npx create-nx-workspace@latest
. Give this monorepo a workspace name, for example 'Google' would be the workspace name and within it you'd have 'Gmail', 'Google Images', etc.nextjs-app
or frontend
or web
.cd <workspace name> && code .
nx add @nx/express
inside the workspace root directory to get node generatorsapi
), set the directory to apps/{name}
(e.g., apps/api
), select express
as the framework, select the Next.js app as the frontendProject
, click Generate
button to automatically create this app. You should now see at least 2 projects in the projects tab within the Nx extension (probably 4 items, if there's an e2e test for each repo).npx nx run {next.js app's name}:build --prod
so e.g., npx nx run nextjs-app:build --prod
, and select the output directory to ./apps/nextjs-app/.next
.npx nx run express-api:build:production
and set the custom start command to nx reset && npx nx run express-api:serve --configuration=production
Now you have one connected repository with the backend express API and frontend Next.js app hosted in different places.
To create shared types (or whatever else) that can be used in both projects:
@nx/node - library
shared-types
, set the directory to apps/shared-types
, expand show more options
, set the import path to @{your project name}/shared-types
.Now, inside the apps/
folder, you'll see the shared-types folder. If you go into apps/shared-types/src/lib/shared-types.ts
, you'll see it exports the following function:
export function sharedTypes(): string {
return 'shared-types';
}
To test out the monorepo, you can open the express app in apps/express-api/src/main.ts
, and do this:
import { sharedTypes } from '@stack-overflow/shared-types';
import express from 'express';
const host = process.env.HOST ?? 'localhost';
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
const shared = sharedTypes();
const app = express();
app.get('/', (req, res) => {
res.send({ message: shared });
});
app.listen(port, host, () => {
console.log(`[ ready ] http://${host}:${port}`);
});
Now, if you run the API (use the Nx extension it's easier), you'll see the following response to a GET request made to /
:
{
"message": "shared-types"
}
And when interfacing with the express server from the next.js app, just have something like "EXTERNAL_API" as an .env variable, and just use process.env.EXTERNAL_API. On dev, set it to localhost and on prod set it to whatever Railway gives you.
For webhooks, use Ngrok and just set up a proxy to the port on your local machine that's running the express server. So if the express server is running on :4000, just run ngrok http 4000
, copy that URL and on dev just set process.env.EXTERNAL_API on the nextjs app to the URL Ngrok gives you.
Upvotes: 2