Two different subdomains in one Next.js routing
You can't split 1 Next.js app between sub-domains for several reasons. From an experience, I had a similar requirement (3 areas) I started with one app split into 3 (using sub paths)
- Assets (css, js libs) leaks between "areas".
- one big app with 3 areas means, each change will require re-deploy all the areas (one big deployable)
- Build time, to build 3 areas will be much longer.
- Each area may introduce different requirement, such as, UI components for admin area, but custom ui components for the "front" area, Auth, translations and many more
Ended up with 3 separate Next.js apps which managed inside yarn workspaces and get deployed by a specific area.
After I've explained my experience, you can achieve a setup with a reverse-proxy such as nginx to map sub-domain to subpath in your next app.
Let's say you have 3 areas, front, admin, users.
www.domain.com/some-page
=> should be mapped to localhost:3000/front/some-page
.
users.domain.com/some-page
=> should be mapped to localhost:3000/users/some-page
.
admin.domain.com/some-page
=> should be mapped to localhost:3000/admin/some-page
.
// www.domain.com.conf
server {
listen 80;
server_name www.domain.com;
access_log /var/log/nginx/access.log main;
root html;
location / {
proxy_pass http://127.0.0.1:3000/front/; // <-- the last slash is important
}
}
// users.domain.com.conf
server {
listen 80;
server_name users.domain.com;
access_log /var/log/nginx/access.log main;
root html;
location / {
proxy_pass http://127.0.0.1:3000/users/; // <-- the last slash is important
}
}
Pay attention
- you will need to rewrite static assets as well.
I manage to create subdomains using a custom express server. This is a blank app with no assets, I haven't tried this yet on a real app with assets (CSS, images, etc)
I have the following pages folder structure:
pages/
├── admin/
│ ├── index.js
│ └── sample-page.js
└── member/
├── index.js
└── accounts/
└── dashboard.js
When you are using next dev
which is the default. This will produce the following routes:
- http://lvh.me:3000/admin
- http://lvh.me:3000/admin/sample-page
- http://lvh.me:3000/member
- http://lvh.me:3000/member/accounts/dashboard
But using the custom server.js
file and running our dev server using node server.js
this will produce the following routes:
- http://admin.lvh.me:3000
- http://admin.lvh.me:3000/sample-page
- http://lvh.me:3000
- http://lvh.me:3000/accounts/dashboard
The content of our server.js
file:
const express = require('express')
const next = require('next')
const vhost = require('vhost')
const port = process.env.PORT || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const mainServer = express()
const adminServer = express()
const memberServer = express()
adminServer.get('/', (req, res) => {
return app.render(req, res, '/admin', req.query)
})
adminServer.get('/*', (req, res) => {
return app.render(req, res, `/admin${req.path}`, req.query)
})
adminServer.all('*', (req, res) => {
return handle(req, res)
})
memberServer.get('/', (req, res) => {
return app.render(req, res, '/member', req.query)
})
memberServer.get('/*', (req, res) => {
return app.render(req, res, `/member${req.path}`, req.query)
})
memberServer.all('*', (req, res) => {
return handle(req, res)
})
mainServer.use(vhost('admin.lvh.me', adminServer))
mainServer.use(vhost('lvh.me', memberServer))
mainServer.use(vhost('www.lvh.me', memberServer))
mainServer.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://lvh.me:${port}`)
})
})
See the repo to see this in action.
Repo: https://github.com/dcangulo/nextjs-subdomain-example