Skip to content

Commit 04a4b0a

Browse files
authored
docs: add custom admin location docs (#15581)
Fixes #13707 - created comprehensive custom admin location guide - updated admin/overview.mdx with cross-references and FAQ - updated custom-components overview with import map regeneration details
1 parent 8e5d56d commit 04a4b0a

File tree

3 files changed

+364
-0
lines changed

3 files changed

+364
-0
lines changed
Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
---
2+
title: Custom Admin Panel Location
3+
label: Custom Admin Panel Location
4+
order: 35
5+
desc: Learn how to move and customize the location of your Payload Admin Panel, including nested routes and custom folder structures.
6+
keywords: admin, customization, routes, folder structure, import map, configuration
7+
---
8+
9+
Payload is flexible about where your Admin Panel lives within your Next.js application. You can customize routes, move folders, and organize your project structure to match your application's needs.
10+
11+
## Common Use Cases
12+
13+
- **Custom admin routes** - Change `/admin` to `/dashboard`, `/cms`, etc.
14+
- **Nested admin panels** - Place Payload at `/admin/content` alongside custom admin routes
15+
- **Multiple admin interfaces** - Organize Payload and custom dashboards together
16+
- **Organizational preferences** - Match your team's folder structure conventions
17+
18+
## Understanding the Payload Folder Structure
19+
20+
By default, Payload creates this structure in your Next.js app:
21+
22+
```
23+
app/ (or src/app/)
24+
├── (payload)/
25+
│ ├── admin/
26+
│ │ ├── [[...segments]]/
27+
│ │ │ ├── not-found.tsx
28+
│ │ │ └── page.tsx
29+
│ │ └── importMap.js
30+
│ ├── api/
31+
│ │ └── [...slug]/
32+
│ │ └── route.ts
33+
│ ├── custom.scss
34+
│ └── layout.tsx
35+
```
36+
37+
- **`(payload)/`** - Parent folder containing all Payload-related routes
38+
- **`admin/`** - Admin Panel UI routes
39+
- **`api/`** - REST API routes
40+
- **`layout.tsx`** - Root layout that imports the import map
41+
- **`importMap.js`** - Auto-generated file mapping component paths (regenerated on startup)
42+
43+
## Scenario 1: Simple Route Change
44+
45+
To change the admin route from `/admin` to `/dashboard`:
46+
47+
**1. Update your Payload Config:**
48+
49+
```ts
50+
import { buildConfig } from 'payload'
51+
52+
export default buildConfig({
53+
// ...
54+
routes: {
55+
admin: '/dashboard', // Changed from '/admin'
56+
},
57+
})
58+
```
59+
60+
**2. Move the folder:**
61+
62+
```bash
63+
# Move the admin folder
64+
mv app/(payload)/admin app/(payload)/dashboard
65+
```
66+
67+
**3. Update the import path in `layout.tsx`:**
68+
69+
Edit `app/(payload)/layout.tsx` and update the import map reference to match the new folder name:
70+
71+
```ts
72+
// Before
73+
import { importMap } from './admin/importMap.js'
74+
75+
// After
76+
import { importMap } from './dashboard/importMap.js'
77+
```
78+
79+
<Banner type="info">
80+
Your IDE may auto-update this import when you move the folder, but it may not.
81+
To catch any stale references to the old path, run a build or type-check
82+
(`pnpm build` or `pnpm tsc --noEmit`) and fix any import errors until it
83+
passes.
84+
</Banner>
85+
86+
**4. Restart your dev server**
87+
88+
Payload will now be available at `/dashboard`.
89+
90+
## Scenario 2: Moving the Entire Payload Folder (Admin Panel and API)
91+
92+
To move both the Payload Admin Panel and API under a custom path, you move the entire `(payload)` folder. This example places everything under `/admin/content`.
93+
94+
<Banner type="info">
95+
Because the `admin/` subfolder inside `(payload)` is a Next.js route segment,
96+
moving `(payload)` to `app/admin/content/(payload)` results in the admin panel
97+
being served at `/admin/content/admin`, not `/admin/content`. Keep this in
98+
mind when choosing your target path and setting `routes.admin`.
99+
</Banner>
100+
101+
**1. Update your Payload Config with all routes and import map settings:**
102+
103+
```ts
104+
import { buildConfig } from 'payload'
105+
import path from 'path'
106+
import { fileURLToPath } from 'url'
107+
108+
const filename = fileURLToPath(import.meta.url)
109+
const dirname = path.dirname(filename)
110+
111+
export default buildConfig({
112+
// ...
113+
routes: {
114+
admin: '/admin/content/admin',
115+
api: '/admin/content/api',
116+
graphQL: '/admin/content/api/graphql',
117+
graphQLPlayground: '/admin/content/api/graphql-playground',
118+
},
119+
admin: {
120+
importMap: {
121+
baseDir: path.resolve(dirname, './src/app/admin/content/(payload)'),
122+
importMapFile: path.resolve(
123+
dirname,
124+
'./src/app/admin/content/(payload)/admin/importMap.js',
125+
),
126+
},
127+
},
128+
})
129+
```
130+
131+
**2. Move the `(payload)` folder:**
132+
133+
```bash
134+
# Create the new directory structure
135+
mkdir -p app/admin/content
136+
137+
# Move the entire (payload) folder
138+
mv app/(payload) app/admin/content/(payload)
139+
```
140+
141+
**3. Update the import path in `layout.tsx`:**
142+
143+
Edit `app/admin/content/(payload)/layout.tsx`:
144+
145+
```ts
146+
// Change this import path to match your new structure
147+
import { importMap } from './admin/importMap.js'
148+
```
149+
150+
The import path should be relative from `layout.tsx` to `importMap.js`. In this case, it remains `'./admin/importMap.js'`.
151+
152+
**4. Regenerate the import map:**
153+
154+
```bash
155+
pnpm payload generate:importmap
156+
```
157+
158+
Your Payload admin is now at `/admin/content/admin` and the API at `/admin/content/api`.
159+
160+
## Scenario 3: Multiple Admin Dashboards
161+
162+
If you want both Payload and custom admin routes under `/admin`:
163+
164+
**Folder Structure:**
165+
166+
```
167+
app/
168+
├── admin/
169+
│ ├── content/ # Payload admin
170+
│ │ └── (payload)/
171+
│ │ ├── admin/
172+
│ │ ├── api/
173+
│ │ └── layout.tsx
174+
│ ├── platform/ # Your custom admin
175+
│ │ ├── dashboard/
176+
│ │ │ └── page.tsx
177+
│ │ └── layout.tsx
178+
│ └── page.tsx # Choose between admins
179+
```
180+
181+
**Configuration:**
182+
183+
```ts
184+
export default buildConfig({
185+
routes: {
186+
admin: '/admin/content',
187+
api: '/admin/content/api',
188+
graphQL: '/admin/content/api/graphql',
189+
graphQLPlayground: '/admin/content/api/graphql-playground',
190+
},
191+
admin: {
192+
importMap: {
193+
baseDir: path.resolve(dirname, './src/app/admin/content/(payload)'),
194+
importMapFile: path.resolve(
195+
dirname,
196+
'./src/app/admin/content/(payload)/admin/importMap.js',
197+
),
198+
},
199+
},
200+
})
201+
```
202+
203+
## Understanding Auto-Generated Files
204+
205+
Not all files in the `(payload)` folder are auto-generated. Here's what you need to know:
206+
207+
| File | Auto-Generated? | Safe to Edit? | When Regenerated? | Notes |
208+
| ------------------------------------- | --------------- | ------------- | ---------------------------- | ------------------------------------------------------------ |
209+
| `layout.tsx` | No | Yes | Never | Created once during setup. Safe to modify import paths. |
210+
| `admin/importMap.js` | Yes | No | Startup, HMR, manual command | Always regenerated. Configure via `admin.importMap` instead. |
211+
| `admin/[[...segments]]/page.tsx` | No | Rarely needed | Never | Part of template. Usually no need to edit. |
212+
| `admin/[[...segments]]/not-found.tsx` | No | Rarely needed | Never | Part of template. Usually no need to edit. |
213+
| `api/[...slug]/route.ts` | No | Rarely needed | Never | Part of template. Usually no need to edit. |
214+
| `custom.scss` | No | Yes | Never | Intended for your custom styles. |
215+
216+
### About the "DO NOT MODIFY" Warning
217+
218+
You may see this warning in `layout.tsx`:
219+
220+
```ts
221+
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
222+
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
223+
```
224+
225+
**This warning is misleading.** The file was generated during initial project setup by `create-payload-app`, but it is **never regenerated** by Payload. It is completely safe to modify this file, especially when customizing your folder structure.
226+
227+
## Editing layout.tsx Safely
228+
229+
When you move the Payload folder, you'll need to update the import path in `layout.tsx`:
230+
231+
```tsx
232+
// app/admin/content/(payload)/layout.tsx
233+
import { importMap } from './admin/importMap.js' // Update this path as needed
234+
```
235+
236+
**What you can safely edit:**
237+
238+
- Import map path (required when moving folders)
239+
- Custom imports for additional functionality
240+
- Custom SCSS imports
241+
- Server function logic (advanced use cases)
242+
243+
**What you should NOT edit:**
244+
245+
- The core `RootLayout` usage (required for Payload)
246+
- The `serverFunction` pattern (required for Payload to work)
247+
- The import map prop to `RootLayout`
248+
249+
## Import Map Regeneration
250+
251+
The `importMap.js` file is automatically regenerated in these scenarios:
252+
253+
- **Application startup** - Every time you start your dev server or production build
254+
- **Hot Module Replacement (HMR)** - When you save changes to component files in development
255+
- **Manual generation** - When you run `pnpm payload generate:importmap`
256+
257+
The import map is **never regenerated** during:
258+
259+
- Normal runtime (only at startup)
260+
- After the production build completes
261+
262+
<Banner type="warning">
263+
**Important:** Never manually edit the `importMap.js` file. Configure
264+
component paths in your Payload config and let Payload regenerate the import
265+
map automatically.
266+
</Banner>
267+
268+
## Troubleshooting
269+
270+
### Import map not found error
271+
272+
If you see an error about the import map not being found:
273+
274+
1. Verify `admin.importMap.importMapFile` points to the correct location
275+
2. Run `pnpm payload generate:importmap` manually
276+
3. Check that the path is absolute, not relative
277+
278+
### Layout.tsx import error
279+
280+
If you see an import error in `layout.tsx`:
281+
282+
1. Verify the import path is relative from `layout.tsx` to `importMap.js`
283+
2. Use `./admin/importMap.js` if importMap is in a sibling `admin` folder
284+
3. Use `./importMap.js` if you moved importMap to the same folder as layout
285+
286+
### Admin panel 404 error
287+
288+
If the admin panel returns 404:
289+
290+
1. Verify `routes.admin` matches your actual folder structure
291+
2. Ensure you moved the entire `(payload)` folder, not just `admin`
292+
3. Check that Next.js is recognizing your new routes
293+
294+
### Components not loading
295+
296+
If custom components aren't loading:
297+
298+
1. Verify `admin.importMap.baseDir` is correct
299+
2. Regenerate the import map: `pnpm payload generate:importmap`
300+
3. Check component paths in your config are relative to `baseDir`
301+
302+
## Additional Resources
303+
304+
- [Admin Panel Overview](./overview)
305+
- [Custom Components](../custom-components/overview)
306+
- [Import Map Configuration](../custom-components/overview#import-map)
307+
- [Customizing Routes](./overview#customizing-routes)
308+
309+
<Banner type="success">
310+
**Need Help?** If you're still having issues, check the [Community
311+
Help](https://payloadcms.com/community-help) or [open a new
312+
issue](https://github.com/payloadcms/payload/issues/new/choose).
313+
</Banner>

docs/admin/overview.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ As shown above, all Payload routes are nested within the `(payload)` route group
5858

5959
The `admin` directory contains all the _pages_ related to the interface itself, whereas the `api` and `graphql` directories contain all the _routes_ related to the [REST API](../rest-api/overview) and [GraphQL API](../graphql/overview). All admin routes are [easily configurable](#customizing-routes) to meet your application's exact requirements.
6060

61+
<Banner type="success">
62+
**Tip:** The `(payload)` folder location is flexible. You can move it to match
63+
your application's structure by updating the `routes` and `admin.importMap`
64+
configuration. See [Customizing Admin Panel Location](./customizing-location)
65+
for step-by-step instructions.
66+
</Banner>
67+
6168
<Banner type="warning">
6269
**Note:** If you don't intend to use the Admin Panel, [REST
6370
API](../rest-api/overview), or [GraphQL API](../graphql/overview), you can
@@ -236,6 +243,12 @@ app
236243
will already be set up correctly.
237244
</Banner>
238245

246+
<Banner type="info">
247+
**Advanced Routing:** For complex scenarios like nesting the admin panel at
248+
custom paths (e.g., `/admin/content`) or organizing multiple admin dashboards,
249+
see [Customizing Admin Panel Location](./customizing-location).
250+
</Banner>
251+
239252
### Admin-level Routes
240253

241254
Admin-level routes are those behind the `/admin` path. These are the routes that are part of the Admin Panel itself, such as the user's account page, the login page, etc.
@@ -406,3 +419,21 @@ The following options are available for the `admin.toast` configuration:
406419
| `expand` | If `true`, will expand the message stack so that all messages are shown simultaneously without user interaction. | `false` |
407420
| `limit` | The maximum number of toasts that can be visible on the screen at once. | `5` |
408421
| `position` | The position of the toast on the screen. | `bottom-right` |
422+
423+
## Frequently Asked Questions
424+
425+
### Can I move the Payload admin panel to a custom location?
426+
427+
Yes! Payload is flexible about where the admin panel lives. You can move it to custom routes like `/dashboard`, `/cms`, or nested paths like `/admin/content`. See [Customizing Admin Panel Location](./customizing-location) for step-by-step instructions.
428+
429+
### Which auto-generated files can I safely modify?
430+
431+
Most files in the `(payload)` folder are only created once and can be safely modified. Only the `importMap.js` file is regenerated automatically. See [Understanding Auto-Generated Files](./customizing-location#understanding-auto-generated-files) for a complete reference table.
432+
433+
### Why does layout.tsx say "DO NOT MODIFY" if I need to edit it?
434+
435+
This warning is misleading. The `layout.tsx` file was generated during initial project setup but is never regenerated by Payload. It is safe to modify, especially when customizing your folder structure. See [About the "DO NOT MODIFY" Warning](./customizing-location#about-the-do-not-modify-warning) for details.
436+
437+
### What happens if I edit the import map file directly?
438+
439+
Don't do this - it will be overwritten on the next startup or HMR. Instead, configure component paths in your Payload config and let Payload regenerate the import map automatically.

docs/custom-components/overview.mdx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,26 @@ In order for Payload to make use of [Component Paths](#component-paths), an "Imp
146146

147147
The Import Map is automatically regenerated at startup and whenever Hot Module Replacement (HMR) runs, or you can run `payload generate:importmap` to manually regenerate it.
148148

149+
#### When Import Maps Are Regenerated
150+
151+
The import map file is automatically regenerated in these scenarios:
152+
153+
- **Application startup** - Every time you start your development server or build your application
154+
- **Hot Module Replacement (HMR)** - When you save changes to component files during development
155+
- **Manual generation** - When you run `payload generate:importmap` or `pnpm payload generate:importmap`
156+
157+
The import map is **never regenerated** during:
158+
159+
- Normal runtime (only at startup)
160+
- After a production build completes
161+
162+
<Banner type="warning">
163+
**Important:** The import map file should never be manually edited. However,
164+
the `layout.tsx` file that imports it is safe to modify when customizing your
165+
folder structure. See [Customizing Admin Panel
166+
Location](../admin/customizing-location) for details.
167+
</Banner>
168+
149169
#### Overriding Import Map Location
150170

151171
Using the `config.admin.importMap.importMapFile` property, you can override the location of the import map. This is useful if you want to place the import map in a different location, or if you want to use a custom file name.

0 commit comments

Comments
 (0)