Profiles
Profiles are overlays on top of your base gws.json. One config file, many ways to deploy it — ci, staging, e2e, minimal, whatever you need.
A profile can:
- Disable services entirely (
enabled: false) - Turn off live file sync and watchers
- Swap in different Dockerfiles or manifest folders
- Point at a remote registry instead of the local one
- Override any service field, individually or via a
*wildcard
The base config keeps its dev-friendly defaults. Profiles only describe what's different.
Define profiles
Add a profiles block to gws.json:
{
"name": "my-project",
"services": [
{ "name": "api", "path": "./api", "fileSync": true, "port": 3000 },
{ "name": "web", "path": "./frontend", "fileSync": true, "port": 80 },
{ "name": "docs", "path": "./docs", "fileSync": true, "port": 8080 }
],
"profiles": {
"ci": {
"description": "CI pipeline — no sync, no docs",
"services": [
{ "name": "*", "fileSync": false },
{ "name": "docs", "enabled": false }
]
},
"minimal": {
"description": "Just the essentials for fast iteration",
"services": [
{ "name": "docs", "enabled": false }
]
},
"staging": {
"description": "Staging — pull images from the remote registry",
"registry": { "mode": "remote", "url": "gcr.io/my-project" },
"services": [
{ "name": "*", "fileSync": false }
]
}
}
}
Use a profile
gws up --profile ci # one-off
gws status # active profile is shown here
GWS_PROFILE=ci gws up # pin via env var (handy in CI scripts)
gws up --profile staging # CLI flag overrides GWS_PROFILE
To switch profiles, stop first:
gws down
gws up --profile staging
What you can override
| Top-level field | Effect |
|---|---|
description | Free-form text shown in gws status |
registry | Replace the registry block (e.g. switch from local to remote) |
services | Array of service overrides — see below |
provision.environments | Override per-environment provisioning settings |
Inside services, each entry is matched by name (or "*" for all services). You can override any field of a service, including:
fileSync,fileSyncIgnore— disable bidirectional syncwatch— disable or replace watch rulesdockerfile— point at a different image build (e.g.Dockerfile.e2e)manifests— point at a different manifest folderexpose,port— reshape runtimeenabled: false— don't deploy this service at all
Environment values come from
gws secret(or yourmanifests/envFrom), not fromgws.json— so there's noenvfield to override here. To inject different values per profile, scope the secret withgws secret set NAME --profile <name>.
Override rules
- Wildcard first.
{ "name": "*", … }is applied to every service before specific overrides. - Specific wins. A
{ "name": "api", … }entry overrides whatever the wildcard set. nulldeletes a property. Use"expose": nullor"watch": nullto remove a field from the base config.enabled: falsefilters the service out entirely — it isn't built, deployed, or synced.- Profiles do not cascade. Each profile is independent of the others; there is no
extends.
Common patterns
CI
"ci": {
"description": "CI — no sync, no dev tools",
"services": [
{ "name": "*", "fileSync": false },
{ "name": "docs", "enabled": false },
{ "name": "storybook", "enabled": false }
]
}
End-to-end testing
Disable sync and watchers, swap to prod-like images. See the full recipe in End-to-end testing.
"e2e": {
"description": "E2E — no sync, no watchers, prod-like images",
"services": [
{ "name": "*", "fileSync": false, "watch": null },
{ "name": "api", "dockerfile": "./api/Dockerfile.e2e", "manifests": "./api/k8s/e2e" },
{ "name": "web", "dockerfile": "./frontend/Dockerfile.e2e", "manifests": "./frontend/k8s/e2e" },
{ "name": "docs", "enabled": false }
]
}
Staging with remote registry
"staging": {
"description": "Staging — remote registry, no sync",
"registry": { "mode": "remote", "url": "gcr.io/my-project" },
"services": [
{ "name": "*", "fileSync": false }
]
}
Low-resource laptop
"low-resource": {
"description": "Skip heavy services on constrained machines",
"services": [
{ "name": "*", "fileSync": false },
{ "name": "heavy-service", "enabled": false }
]
}
Deploy a single subset
In a multi-repo project, profiles still target every service in the centralized gws.json regardless of which child repo it lives in:
"api-only": {
"description": "Only the API services",
"services": [
{ "name": "web", "enabled": false },
{ "name": "ssr", "enabled": false }
]
}
Validate
gws config validate
Common errors:
Profile "<name>" not found— typo, or the profile isn't defined ingws.jsonProfile override for service "<name>" targets non-existent service— the service was renamed or deleted from the base configProfile conflict detected. Current deployment uses "<other>" profile.— you forgot togws downbefore switching
See also
gws profile— list, validate, and inspect profiles from the CLI- End-to-end testing — full recipe using an
e2eprofile - Watch Configuration — what
watch: nullactually disables - Configuration profiles reference — authoritative source-of-truth doc
ProfileConfigschema — the TypeScript interface