Skip to content

Commit ede59ac

Browse files
authored
chore: monorepo devcontainer support, refactor db adapter and docker start script (#16396)
## Devcontainers Adds dev container configuration, so contributors can open the repo in VS Code without setting up Node, pnpm, or Docker on their own machine. Works for both "Reopen in Container" (your local clone bind-mounted in) and "Clone Repository in Container Volume" (a fresh clone inside an isolated Docker volume, useful when running multiple parallel sessions against the same repo without them stepping on each other). `test/generateDatabaseAdapter.ts` was renamed to `test/dbAdapters.ts` and is the source of truth for anything db-adapter-related in one place: the source templates the codegen writes out, and the host/port/env-var defaults per adapter, which the new `assertDbReachable.ts` function uses to probe services. This should enable running multiple agents conflict-free ## DB Connection probe + docker:start script improvements `assertDbReachable` is now run within `pnpm dev`. If the db connection fails, you now get immediate feedback through a helpful error, instead of having to wait for Next.js to compile and then be thrown off by a cryptic db seed error: <img width="852" height="488" alt="screenshot 2026-04-26 at 15 26 12@2x" src="https://github.com/user-attachments/assets/aecfee0a-20eb-4d25-9215-256f8c8f5f8a" /> `pnpm docker:start` is now an interactive picker. You can still pass profile names as args (`pnpm docker:start postgres mongodb`) to skip the prompt: <img width="898" height="348" alt="screenshot 2026-04-26 at 15 28 04@2x" src="https://github.com/user-attachments/assets/7d4b8f3d-89a5-46b7-b3ca-887a793246b1" /> These changes encourages contributors not to start every single service we have available (uses around 4gb of ram), and only start the database service that you're using => much less memory usage. --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1214135483864575
1 parent d2538f9 commit ede59ac

26 files changed

Lines changed: 607 additions & 132 deletions

.devcontainer/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PAYLOAD_DATABASE=sqlite

.devcontainer/devcontainer.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"name": "Payload Monorepo",
3+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
4+
"features": {
5+
"ghcr.io/payloadcms/devcontainer-features/mise-bootstrap:1": {},
6+
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
7+
"ghcr.io/devcontainers/features/common-utils:2": {
8+
"configureZshAsDefaultShell": true,
9+
"installZsh": true,
10+
"installOhMyZsh": true,
11+
"installOhMyZshConfig": true,
12+
"upgradePackages": true
13+
}
14+
},
15+
// Runs before feature postCreateCommands so the named volume is writable
16+
// by the time mise-bootstrap tries to install into node_modules.
17+
"onCreateCommand": "sudo chown vscode:vscode ${containerWorkspaceFolder}/node_modules",
18+
// setup.sh auto-detects bind-mount vs volume-clone mode and handles both.
19+
"postCreateCommand": ".devcontainer/setup.sh",
20+
// Only the Next.js dev server should be forwarded
21+
"forwardPorts": [3000],
22+
"portsAttributes": {
23+
"3000": {
24+
"label": "Next Dev Server"
25+
}
26+
},
27+
"customizations": {
28+
"vscode": {
29+
"extensions": [
30+
"anthropic.claude-code",
31+
"dbaeumer.vscode-eslint",
32+
"esbenp.prettier-vscode",
33+
"eamodio.gitlens",
34+
"hverlin.mise-vscode",
35+
"stylelint.vscode-stylelint",
36+
"vitest.explorer",
37+
"ms-playwright.playwright"
38+
],
39+
"settings": {
40+
"terminal.integrated.defaultProfile.linux": "zsh",
41+
"terminal.integrated.profiles.linux": {
42+
"zsh": {
43+
"path": "zsh"
44+
}
45+
},
46+
// Stop VS Code from auto-forwarding every ephemeral port a process opens.
47+
// Only ports in `forwardPorts` above are exposed.
48+
"remote.autoForwardPorts": false
49+
}
50+
}
51+
},
52+
// Allows us to detect whether we are within a devcontainer
53+
"containerEnv": {
54+
"DEVCONTAINER": "true"
55+
},
56+
// node_modules volume: isolates linux-arm64 installs from darwin-arm64 host
57+
// files in bind-mount mode.
58+
"mounts": [
59+
"source=${containerWorkspaceFolderBasename}-node-modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
60+
]
61+
}

.devcontainer/setup.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
WS="$(pwd)"
5+
6+
if [ "$(stat -c '%u' "$WS")" = "0" ]; then
7+
# Volume-clone: whole workspace was cloned as root; rehome it.
8+
sudo chown -R vscode:vscode "$WS"
9+
else
10+
# Bind-mount: only the fresh node_modules named volume is root-owned.
11+
sudo chown vscode:vscode "$WS/node_modules"
12+
fi
13+
14+
# Seed .env when absent
15+
[ -f .env ] || cp .devcontainer/.env.example .env

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ jobs:
407407
env:
408408
PLAYWRIGHT_JSON_OUTPUT_NAME: results_${{ matrix.suite }}_${{ matrix.shard }}.json
409409
NEXT_TELEMETRY_DISABLED: 1
410+
PAYLOAD_DATABASE: mongodb
410411

411412
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
412413
if: always()

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ dist
55
!/.idea/runConfigurations
66
/.idea/runConfigurations/_template*
77
!/.idea/payload.iml
8+
.pnpm-store
89

910
# Local AI Agent files
1011
AGENTS.local.md
@@ -18,7 +19,6 @@ CLAUDE.local.md
1819

1920
test/packed
2021
test-results
21-
.devcontainer
2222
.localstack
2323
/migrations
2424
.localstack

CONTRIBUTING.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@ All services are defined in a single `test/docker-compose.yml` using Docker Comp
166166

167167
SQLite databases don't require Docker — they're stored as files in the project.
168168

169+
### Development with Devcontainers
170+
171+
You can run the entire development environment inside a devcontainer.
172+
173+
**Prerequisites:**
174+
175+
- Docker or [OrbStack](https://orbstack.dev) (recommended on macOS for better performance)
176+
- One of:
177+
- VS Code with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), or
178+
- The [`@devcontainers/cli`](https://github.com/devcontainers/cli)
179+
180+
**Start the container — pick one:**
181+
182+
- **VS Code:** Open the repo and click "Reopen in Container" when prompted (or run `Dev Containers: Reopen in Container` from the command palette).
183+
- **CLI (any editor):** From the repo root, run `devcontainer up`, then `devcontainer exec zsh` for a shell. To attach an editor, point it at the running container - e.g. JetBrains "Dev Containers" plugin, Cursor / VS Code "Attach to Running Container", or just use the terminal.
184+
185+
**Then, inside the container:**
186+
187+
1. Run `pnpm docker:start` if you're not using sqlite
188+
2. Run `pnpm dev <test suite name>`
189+
190+
The default `PAYLOAD_DATABASE` inside the devcontainer is `sqlite`, so the `pnpm docker:start` step is only needed when you switch to mongodb/postgres.
191+
169192
### Testing with your own database
170193

171194
If you wish to use your own MongoDB database for the `test` directory instead of using the docker database, add the following to your `.env` file:

package.json

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@
8282
"dev:prod": "cross-env NODE_OPTIONS=--no-deprecation tsx ./test/dev.ts --prod",
8383
"dev:vercel-postgres": "cross-env PAYLOAD_DATABASE=vercel-postgres pnpm runts ./test/dev.ts",
8484
"devsafe": "node ./scripts/delete-recursively.js '**/.next' && pnpm dev",
85-
"docker:clean": "node ./scripts/docker-clean.js",
86-
"docker:start": "pnpm docker:clean && docker compose -f test/docker-compose.yml --profile all up -d --wait",
85+
"docker:clean": "node ./scripts/docker-clean.ts",
86+
"docker:start": "node ./scripts/docker-start.ts",
8787
"docker:test": "pnpm runts test/__helpers/shared/db/mongodb/run-test-connection.ts && pnpm runts test/__helpers/shared/db/mongodb-atlas/run-test-connection.ts",
8888
"force:build": "pnpm run build:core:force",
8989
"lint": "turbo run lint --log-order=grouped --continue --filter \"!blank\" --filter \"!website\" --filter \"!ecommerce\"",
@@ -178,6 +178,7 @@
178178
"devDependencies": {
179179
"@ai-sdk/openai": "3.0.30",
180180
"@axe-core/playwright": "4.11.0",
181+
"@clack/prompts": "1.2.0",
181182
"@libsql/client": "0.14.0",
182183
"@next/bundle-analyzer": "16.2.3",
183184
"@payloadcms/db-postgres": "workspace:*",
@@ -245,10 +246,6 @@
245246
"zod": "4.3.6"
246247
},
247248
"packageManager": "pnpm@10.27.0",
248-
"engines": {
249-
"node": "^18.20.2 || >=20.9.0",
250-
"pnpm": "^10.27.0"
251-
},
252249
"pnpm": {
253250
"onlyBuiltDependencies": [
254251
"@parcel/watcher",

0 commit comments

Comments
 (0)