Core Concepts
Understanding the key ideas behind SkyState will help you use it effectively and avoid common mistakes. This page covers the building blocks: accounts, projects, environments, configs, and versioning.
Accounts
An account is the top-level identity in SkyState. It maps to one GitHub user and has:
- A unique account slug — a short lowercase identifier used in public URLs and the CLI. It is derived from your GitHub username and can be changed in account settings.
- A subscription tier —
free,hobby, orpro— which determines how many projects you can create and how many API requests are counted per month.
Authentication is done via GitHub OAuth. There is no username/password — your GitHub identity is the credential.
Projects
A project is the unit of organization for a set of related configs. You might have one project per application, or one project per service in a larger system.
Each project has:
- A name — a human-readable display name.
- A slug — a lowercase alphanumeric identifier unique within your account, used in CLI commands and API paths. Example:
my-api,web-app,marketing-site. - Three fixed environments:
development,staging, andproduction.
Projects are created from the dashboard or with skystate project create.
A local repository is linked to a project by skystate init, which writes the project slug to skystate.json at the repository root.
Project Limits by Tier
| Tier | Max Projects |
|---|---|
| Free | 3 |
| Hobby | 7 |
| Pro | 15 |
Environments
Every project has exactly three environments: development, staging, and production. They are created automatically when the project is created — there is nothing to provision.
Environments are isolated from one another. Pushing a config to development has no effect on staging or production. This lets you iterate safely:
- Push and test in
development. - Promote to
stagingwhen the change is ready. - Promote to
productionwhen staging is verified.
Promoting Between Environments
The skystate promote command copies the latest config from one environment to another:
skystate promote --from staging --to productionThis creates a new version in the target environment that is identical to the source. It does not modify the source environment.
Environment Slugs and Aliases
CLI commands accept both full names and short aliases:
| Full name | Alias |
|---|---|
development | dev |
staging | stg |
production | prod |
For example, skystate push config.json --env dev is equivalent to --env development.
Configs
A config is a JSON object stored for a specific project and environment. It holds all the remote values your application reads at runtime.
Key properties of configs:
- JSON objects only — configs must be JSON objects (
{}), not arrays or primitives. - Flat or nested — you can use dotted keys like
"banner.enabled"or nested objects like{"banner": {"enabled": true}}. The SDK reads individual keys by path. - Read-only for clients — end users of your application can read configs via the SDK (using a dev key or a public project key), but cannot write to them. Only authenticated admin actions (CLI, dashboard, or your backend using your JWT) can push changes.
- Versioned — every push creates an immutable new version. Previous versions are retained according to your tier's retention policy.
Example Config
{
"maintenance.enabled": false,
"banner.enabled": true,
"banner.text": "Spring sale — 20% off all plans!",
"banner.color": "#3b82f6",
"features.darkMode": false,
"features.maxItems": 10,
"limits.maxUploadMb": 25
}Config Size
Each config is stored as a JSON blob. The size limits depend on your subscription tier. Configs that exceed the limit are rejected at push time with a clear error message.
Semantic Versioning
Every config is versioned using semantic versioning (major.minor.patch). SkyState automatically determines the appropriate version bump based on what changed between the previous version and the new one.
Automatic Bump Detection
When you run skystate push, the CLI fetches the current config and compares it to the file you are pushing:
| What changed | Bump type | Example |
|---|---|---|
| A key was removed | major | 1.2.3 → 2.0.0 |
| A value's type changed (e.g. string became boolean) | major | 1.2.3 → 2.0.0 |
| A new key was added | minor | 1.2.3 → 1.3.0 |
| Only values changed | patch | 1.2.3 → 1.2.4 |
| No changes detected | patch | 1.2.3 → 1.2.4 |
The first push to any environment always creates version 1.0.0.
Overriding the Bump Type
You can override automatic detection with the --bump flag:
skystate push config.json --env production --bump minorValid values: major, minor, patch.
Major Milestone Flag
The --major flag marks a version as a major milestone for retention purposes. This is independent of the semver bump type:
skystate push config.json --env production --bump patch --majorMajor milestones are retained longer than ordinary versions under retention pruning policies.
Viewing Version History
Use skystate show to see the current version of a config:
skystate show --env productionUse skystate diff to compare two versions:
skystate diff --env production --from 1.0.0 --to 2.0.0API Keys
SkyState uses two types of API keys.
Dev API Keys
A dev API key (sk_dev_...) is generated by skystate init for local development. It is:
- Scoped to a single project's
developmentenvironment only. - Read-write — the SDK uses it to auto-create config keys when they are not found on the server (dev-mode auto-provisioning).
- Written to your project's
.envfile asSKYSTATE_DEV_KEY. - Safe to expose to the client bundle in development (Vite, Next.js, etc. via environment variables). The server rejects it for
stagingorproductionrequests, so accidental leaks cannot affect live environments.
Dev API keys can be rotated at any time from the dashboard (Settings → Dev Keys) or by re-running skystate init.
Never commit your .env file. skystate init offers to add .env to .gitignore automatically.
JWT (Admin Credential)
When you run skystate login, the CLI stores a JWT at ~/.config/skystate/credentials.json. This token:
- Is tied to your account and grants full admin access to all your projects.
- Expires after 30 minutes and is refreshed transparently.
- Should never be shared or committed.
The CLI reads this token automatically for all skystate commands.
Configuration Files
SkyState uses two configuration files:
skystate.json (Project Config)
Written to the repository root by skystate init. Contains the project slug that links this repo to a SkyState project.
{
"project_slug": "my-app"
}Commit this file. It is not sensitive and must be present for skystate push and skystate show to work without extra flags.
~/.config/skystate/config.json (Global CLI Config)
Stores your personal CLI preferences. Written by skystate config set.
{
"api_url": "https://api.skystate.io",
"format": "table"
}Available keys:
| Key | Default | Description |
|---|---|---|
api_url | https://api.skystate.io | API base URL. Override with SKYSTATE_API_URL env var. |
default_project | (empty) | Fallback project slug when not in a repo with skystate.json. |
default_env | (empty) | Fallback environment for push/show/diff commands. |
format | table | Default output format: table, json, or plain. |
Manage this file with skystate config set <key> <value>, skystate config get <key>, and skystate config list.
.env (Dev Key)
Written to the repository root by skystate init. Contains the dev API key as SKYSTATE_DEV_KEY.
SKYSTATE_DEV_KEY=sk_dev_abc123...Do not commit this file. It contains a secret credential. Add it to .gitignore.
The Network-First Model
The SDK follows a network-first architecture. When a component mounts:
- The SDK immediately returns the
defaultValueyou provided in code, withisLoading: true. - The SDK fetches the latest config from the server.
- On success:
datais updated to the server value,isLoading: false. - On failure:
datastays ondefaultValue,isLoading: false,erroris populated.
This means your app is always functional even if SkyState is unreachable — it falls back to your hardcoded defaults. The skystate.json file on disk is not read at runtime; it is a developer tool for CLI operations only.