You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add sync-ready gate, default protocol/domain, update docs with benchmark findings
- Sync-ready gate: containers wait for Mutagen sync via marker file,
no more while-loop workarounds needed in commands
- Default routing.protocol to http when port is set
- Default domain to {name}.{scdev_domain} when not set
- Update all docs: .pnpm-store must be in mutagen ignore (prevents
platform-specific native binaries syncing between glibc/musl)
- Update examples to use pnpm and node:22-alpine throughout
- Update benchmark numbers with true cold start measurements
- Remove node_modules named volume pattern from recommendations
(mutagen ignore is the correct approach)
Copy file name to clipboardExpand all lines: CLAUDE.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,9 +53,11 @@ When adding a new shared service (easy to miss steps):
53
53
54
54
## Gotchas
55
55
56
-
- Mutagen ignored paths are NOT synced in either direction. This breaks IDE autocomplete if `vendor/` or `node_modules/` are ignored.
56
+
- Mutagen ignored paths are NOT synced in either direction. `node_modules` and `.pnpm-store` should always be ignored for Node.js projects - they stay inside the container for native speed. IDE autocomplete still works because `pnpm install` also runs on the host (or the IDE uses the host's own node_modules).
57
+
- For pnpm projects, `.pnpm-store` MUST be in the mutagen ignore list. pnpm creates a ~500MB content-addressable store inside the project dir when running in a container. Without ignoring it, platform-specific native binaries (glibc vs musl) sync to the host and break when the container image changes.
57
58
- Only directory bind mounts are synced via Mutagen. Single-file mounts stay as regular bind mounts.
58
59
- The docs page (`docs.shared.<domain>`) doubles as a 404 catch-all via Traefik - unmatched URLs redirect there.
60
+
- The sync-ready gate (`/.scdev-sync-ready` marker) automatically holds the container's command until Mutagen sync completes. No need for `while [ ! -f ... ]` workarounds in commands.
- ${PROJECTPATH}:/app# mounts your project directory into the container
82
+
- ${PROJECTPATH}:/app
83
83
routing:
84
84
port: 3000
85
+
86
+
mutagen:
87
+
ignore:
88
+
- node_modules
89
+
- .pnpm-store
90
+
- .nuxt
85
91
```
86
92
87
93
`${PROJECTPATH}` is resolved automatically to your project's absolute path. Other available variables: `${PROJECTNAME}`, `${PROJECTDIR}`, `${SCDEV_DOMAIN}`.
@@ -124,25 +130,30 @@ Every project and shared service gets locally-trusted HTTPS certificates. Your b
124
130
125
131
File sharing between your host and containers is notoriously slow on macOS. scdev automatically syncs files at native speed - no configuration needed. On Linux this isn't needed (already fast).
126
132
127
-
How much difference does it make? We benchmarked `pnpm install` on a Nuxt app:
133
+
How much difference does it make? We benchmarked a Nuxt 4 app with ~1000 dependencies:
That's a **7x speedup** on dependency installation. The trick: scdev syncs your source code via fast file sync, while keeping `node_modules` inside the container where filesystem operations are native speed.
141
+
That's a **5x speedup** on cold start and **instant** warm restarts. The trick: scdev syncs your source code via fast file sync, while keeping `node_modules` and other generated files inside the container where filesystem operations are native speed.
135
142
136
-
Exclude paths you don't need synced:
143
+
Exclude paths you don't need synced back to the host:
137
144
138
145
```yaml
139
146
mutagen:
140
147
ignore:
141
148
- node_modules
149
+
- .pnpm-store # pnpm's content-addressable store - platform-specific, don't sync
142
150
- .nuxt
151
+
- .output
143
152
- var/cache
144
153
```
145
154
155
+
**Important:** Always add `.pnpm-store` to the ignore list for pnpm projects. pnpm creates its package store inside the project directory when running in a container. Without ignoring it, ~500MB of platform-specific binaries sync to the host, causing slow syncs and broken native modules when switching images.
156
+
146
157
### TCP/UDP Routing
147
158
148
159
Beyond HTTPS, scdev can expose raw TCP and UDP ports. This lets you connect to a database inside a project from your host using tools like DBeaver, pgAdmin, or `psql`:
@@ -167,18 +178,18 @@ Multiple projects can expose different ports without conflicts. Works for MySQL,
167
178
168
179
### Volumes
169
180
170
-
**Bind mounts** (`${PROJECTPATH}:/app`) sync your source code into the container. Edits on the host are reflected immediately. On macOS, scdev handles fast sync automatically.
181
+
**Bind mounts** (`${PROJECTPATH}:/app`) sync your source code into the container. Edits on the host are reflected immediately. On macOS, scdev handles fast sync automatically via Mutagen. Add `node_modules`, `.pnpm-store`, and build caches to `mutagen.ignore` so they stay inside the container (fast) and don't sync back to the host.
171
182
172
-
**Named volumes** (`node_modules:/app/node_modules`) are persistent storage managed by scdev. Use these for dependencies, database files, and caches - things that are huge, change constantly, and would kill sync performance:
183
+
**Named volumes** (`db_data:/var/lib/postgresql/data`) are persistent storage managed by scdev. Use these for data that must survive `scdev down` - database files, uploaded assets, SQLite databases:
173
184
174
185
```yaml
175
186
volumes:
176
187
- ${PROJECTPATH}:/app # your source code (synced to host)
177
-
- node_modules:/app/node_modules # dependencies (stays in container, fast)
178
-
- db_data:/var/lib/postgresql/data # database files (persists across restarts)
188
+
- db_data:/var/lib/postgresql/data # database files (persists across down)
189
+
- data:/app/data # SQLite, uploads, etc.
179
190
```
180
191
181
-
Named volumes persist across `scdev stop`/`scdev start` and are removed with `scdev down -v`. No separate declaration needed - scdev discovers them automatically.
192
+
Named volumes persist across `scdev stop`/`scdev start` AND `scdev down`. Only removed with `scdev down -v`. No separate declaration needed - scdev discovers them automatically.
182
193
183
194
### Custom Commands
184
195
@@ -194,15 +205,15 @@ Every project has recurring tasks: install deps, run migrations, seed data, run
194
205
```bash
195
206
# .scdev/commands/setup.just
196
207
default:
197
-
scdev exec app npm ci
208
+
scdev exec app pnpm ci
198
209
scdev exec app npx prisma db push
199
210
200
211
# .scdev/commands/test.just
201
212
default:
202
-
scdev exec app npm test
213
+
scdev exec app pnpm test
203
214
204
215
watch:
205
-
scdev exec app npm test -- --watch
216
+
scdev exec app pnpm test -- --watch
206
217
```
207
218
208
219
```bash
@@ -233,7 +244,7 @@ scdev down -v # Remove everything including volumes
0 commit comments