diff --git a/Applications/Overview.mdx b/Applications/Overview.mdx
new file mode 100644
index 00000000..0b5e0d51
--- /dev/null
+++ b/Applications/Overview.mdx
@@ -0,0 +1,602 @@
+---
+title: 'Applications'
+sidebarTitle: 'Overview'
+description: 'Deploy long-running services as publicly accessible endpoints with revision management, canary traffic splitting, and custom URLs.'
+---
+
+Applications are long-running deployed services that run your custom code as publicly accessible endpoints. They are ideal for web servers, APIs, dashboards, and any service that needs to be always-on.
+
+Applications run on Blaxel's mk3 micro-VM infrastructure and support revision management with canary traffic splitting, custom domain URLs, and deployment from source code, images, or forked sandboxes.
+
+
+Application Runtime is currently in preview.
+
+
+## Key concepts
+
+- **Application**: A long-running deployment that serves traffic on a public URL.
+- **Revision**: An immutable snapshot of the application code, image, environment, and memory configuration. Each deploy creates a new revision (max 5 kept).
+- **Traffic splitting**: Route traffic between an active revision and a canary revision using percentage-based splitting.
+- **Sticky sessions**: Optional session affinity via `stickySessionTtl` to keep users on the same revision.
+- **Custom URLs**: Map verified custom domains to your application.
+
+## Create an application
+
+### Using the SDKs
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+const app = await ApplicationInstance.create({
+ name: "my-app",
+ image: "my-registry/my-image:latest",
+ memory: 2048,
+ region: "us-pdx-1",
+ envs: [{ name: "NODE_ENV", value: "production" }],
+});
+```
+
+```python Python
+import asyncio
+from blaxel.core import ApplicationInstance
+
+async def main():
+ app = await ApplicationInstance.create({
+ "name": "my-app",
+ "image": "my-registry/my-image:latest",
+ "memory": 2048,
+ "region": "us-pdx-1",
+ "envs": [{"name": "NODE_ENV", "value": "production"}],
+ })
+
+if __name__ == "__main__":
+ asyncio.run(main())
+```
+
+```go Go
+import blaxel "github.com/blaxel-ai/sdk-go"
+
+app, err := client.Applications.Create(ctx, blaxel.ApplicationCreateParams{
+ Body: blaxel.Application{
+ Metadata: blaxel.Metadata{Name: "my-app"},
+ Spec: blaxel.ApplicationSpec{
+ Enabled: true,
+ Region: "us-pdx-1",
+ Revisions: []blaxel.AppRevision{{
+ Image: "my-registry/my-image:latest",
+ Memory: 2048,
+ Envs: []blaxel.Env{{Name: "NODE_ENV", Value: "production"}},
+ }},
+ },
+ },
+})
+```
+
+
+
+### Using the CLI
+
+Deploy from a project directory containing a `blaxel.toml`:
+
+```bash
+bl deploy --type application
+```
+
+Example `blaxel.toml`:
+
+```toml
+name = "my-app"
+type = "application"
+workspace = "my-workspace"
+
+[env]
+NODE_ENV = "production"
+
+[deploy]
+region = "us-pdx-1"
+memory = 2048
+```
+
+To deploy a pre-built image, set the `image` field:
+
+```toml
+name = "my-app"
+type = "application"
+workspace = "my-workspace"
+image = "my-registry/my-image:latest"
+```
+
+### Using the HTTP API
+
+```bash
+curl -X POST https://api.blaxel.ai/v0/applications \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "metadata": { "name": "my-app" },
+ "spec": {
+ "enabled": true,
+ "region": "us-pdx-1",
+ "revisions": [{
+ "image": "my-registry/my-image:latest",
+ "memory": 2048,
+ "envs": [{ "name": "NODE_ENV", "value": "production" }]
+ }]
+ }
+ }'
+```
+
+## Retrieve an application
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+const app = await ApplicationInstance.get("my-app");
+console.log(app.status);
+```
+
+```python Python
+from blaxel.core import ApplicationInstance
+
+app = await ApplicationInstance.get("my-app")
+print(app.status)
+```
+
+```go Go
+app, err := client.Applications.Get(ctx, "my-app", blaxel.ApplicationGetParams{})
+```
+
+
+
+CLI:
+
+```bash
+bl get applications
+```
+
+HTTP API:
+
+```bash
+curl https://api.blaxel.ai/v0/applications/my-app \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace"
+```
+
+## List applications
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+const apps = await ApplicationInstance.list();
+```
+
+```python Python
+from blaxel.core import ApplicationInstance
+
+apps = await ApplicationInstance.list()
+```
+
+```go Go
+apps, err := client.Applications.List(ctx, blaxel.ApplicationListParams{})
+```
+
+
+
+CLI:
+
+```bash
+bl get applications
+```
+
+HTTP API:
+
+```bash
+curl https://api.blaxel.ai/v0/applications \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace"
+```
+
+## Update an application
+
+Updating an application with a new image or configuration creates a new revision.
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+const app = await ApplicationInstance.get("my-app");
+const updated = await app.update({
+ image: "my-registry/my-image:v2",
+ memory: 4096,
+});
+```
+
+```python Python
+from blaxel.core import ApplicationInstance
+
+app = await ApplicationInstance.get("my-app")
+updated = await app.update({
+ "image": "my-registry/my-image:v2",
+ "memory": 4096,
+})
+```
+
+```go Go
+updated, err := client.Applications.Update(ctx, "my-app", blaxel.ApplicationUpdateParams{
+ Body: blaxel.Application{
+ Metadata: blaxel.Metadata{Name: "my-app"},
+ Spec: blaxel.ApplicationSpec{
+ Enabled: true,
+ Region: "us-pdx-1",
+ Revisions: []blaxel.AppRevision{{
+ Image: "my-registry/my-image:v2",
+ Memory: 4096,
+ }},
+ },
+ },
+})
+```
+
+
+
+HTTP API:
+
+```bash
+curl -X PUT https://api.blaxel.ai/v0/applications/my-app \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "metadata": { "name": "my-app" },
+ "spec": {
+ "enabled": true,
+ "region": "us-pdx-1",
+ "revisions": [{
+ "image": "my-registry/my-image:v2",
+ "memory": 4096
+ }]
+ }
+ }'
+```
+
+## Delete an application
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+await ApplicationInstance.delete("my-app");
+```
+
+```python Python
+from blaxel.core import ApplicationInstance
+
+await ApplicationInstance.delete("my-app")
+```
+
+```go Go
+err := client.Applications.Delete(ctx, "my-app")
+```
+
+
+
+CLI:
+
+```bash
+bl delete application my-app
+```
+
+HTTP API:
+
+```bash
+curl -X DELETE https://api.blaxel.ai/v0/applications/my-app \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace"
+```
+
+## Revisions
+
+Each deploy creates a new revision. A maximum of 5 revisions are kept per application. Revisions contain the image, environment variables, memory allocation, and port configuration.
+
+### List revisions
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+const app = await ApplicationInstance.get("my-app");
+const revisions = await app.listRevisions();
+```
+
+```python Python
+from blaxel.core import ApplicationInstance
+
+app = await ApplicationInstance.get("my-app")
+revisions = await app.list_revisions()
+```
+
+```go Go
+revisions, err := client.Applications.ListRevisions(ctx, "my-app")
+```
+
+
+
+HTTP API:
+
+```bash
+curl https://api.blaxel.ai/v0/applications/my-app/revisions \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace"
+```
+
+### Traffic splitting
+
+Control how traffic is distributed between revisions using the `traffic` parameter on deploy:
+
+- `traffic=100` (default): the new revision receives 100% of traffic (full deployment).
+- `traffic=1-99`: canary deployment. The new revision receives this percentage, and the active revision receives the rest.
+- `traffic=0`: staging deployment. The new revision is deployed but receives no traffic.
+
+To deploy a canary revision via the HTTP API:
+
+```bash
+curl -X PUT https://api.blaxel.ai/v0/applications/my-app \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "metadata": { "name": "my-app" },
+ "spec": {
+ "enabled": true,
+ "region": "us-pdx-1",
+ "revision": {
+ "traffic": 20
+ },
+ "revisions": [{
+ "image": "my-registry/my-image:v3",
+ "memory": 2048
+ }]
+ }
+ }'
+```
+
+### Sticky sessions
+
+Enable sticky sessions to keep users routed to the same revision for the duration of the TTL:
+
+```json
+{
+ "spec": {
+ "revision": {
+ "stickySessionTtl": 3600
+ }
+ }
+}
+```
+
+Setting `stickySessionTtl` to `0` disables sticky sessions.
+
+## Custom URLs
+
+By default, applications are accessible at a generated URL. You can configure custom URLs using verified custom domains in your workspace.
+
+### Create or update an application with custom URLs
+
+Pass the `urls` field in the application spec to attach a verified custom domain.
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+const app = await ApplicationInstance.create({
+ metadata: {
+ name: "my-app",
+ },
+ spec: {
+ enabled: true,
+ region: "us-pdx-1",
+ urls: [{ domain: "app.example.com" }],
+ revisions: [{
+ image: "my-registry/my-image:latest",
+ memory: 2048,
+ }],
+ },
+});
+```
+
+```python Python
+from blaxel.core import ApplicationInstance
+
+app = await ApplicationInstance.create({
+ "metadata": {"name": "my-app"},
+ "spec": {
+ "enabled": True,
+ "region": "us-pdx-1",
+ "urls": [{"domain": "app.example.com"}],
+ "revisions": [{
+ "image": "my-registry/my-image:latest",
+ "memory": 2048,
+ }],
+ },
+})
+```
+
+```go Go
+app, err := client.Applications.Create(ctx, blaxel.ApplicationCreateParams{
+ Body: blaxel.Application{
+ Metadata: blaxel.Metadata{Name: "my-app"},
+ Spec: blaxel.ApplicationSpec{
+ Enabled: true,
+ Region: "us-pdx-1",
+ Urls: []blaxel.AppUrl{{Domain: "app.example.com"}},
+ Revisions: []blaxel.AppRevision{{
+ Image: "my-registry/my-image:latest",
+ Memory: 2048,
+ }},
+ },
+ },
+})
+```
+
+
+
+To add a custom URL to an existing application, use update:
+
+
+
+```typescript TypeScript
+import { ApplicationInstance } from "@blaxel/core";
+
+const app = await ApplicationInstance.get("my-app");
+const updated = await ApplicationInstance.update("my-app", {
+ metadata: app.metadata,
+ spec: {
+ ...app.spec,
+ urls: [{ domain: "app.example.com" }],
+ },
+});
+```
+
+```python Python
+from blaxel.core import ApplicationInstance
+
+app = await ApplicationInstance.get("my-app")
+updated = await app.update({
+ "metadata": app.metadata,
+ "spec": {
+ **app.spec,
+ "urls": [{"domain": "app.example.com"}],
+ },
+})
+```
+
+```go Go
+updated, err := client.Applications.Update(ctx, "my-app", blaxel.ApplicationUpdateParams{
+ Body: blaxel.Application{
+ Metadata: existing.Metadata,
+ Spec: blaxel.ApplicationSpec{
+ Enabled: existing.Spec.Enabled,
+ Region: existing.Spec.Region,
+ Urls: []blaxel.AppUrl{{Domain: "app.example.com"}},
+ Revisions: existing.Spec.Revisions,
+ },
+ },
+})
+```
+
+
+
+HTTP API:
+
+```bash
+curl -X PUT https://api.blaxel.ai/v0/applications/my-app \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "metadata": { "name": "my-app" },
+ "spec": {
+ "enabled": true,
+ "region": "us-pdx-1",
+ "urls": [
+ { "domain": "app.example.com" }
+ ],
+ "revisions": [{
+ "image": "my-registry/my-image:latest",
+ "memory": 2048
+ }]
+ }
+ }'
+```
+
+For wildcard custom domains (e.g. `*.sandbox.example.com`), use the `subdomain` field:
+
+```json
+{
+ "spec": {
+ "urls": [
+ { "subdomain": "myapp", "domain": "sandbox.example.com" }
+ ]
+ }
+}
+```
+
+### Create a custom domain for an application
+
+You can also create a custom domain scoped to a specific application using the dedicated endpoint. After creation, configure DNS records and verify domain ownership before it becomes active.
+
+```bash
+curl -X POST https://api.blaxel.ai/v0/applications/my-app/customdomains \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "metadata": { "name": "app.example.com" },
+ "spec": {
+ "type": "applications",
+ "domain": "app.example.com",
+ "region": "us-pdx-1"
+ }
+ }'
+```
+
+
+The domain must be a verified custom domain in your workspace. Custom domain verification is managed in the [Infrastructure section](/Infrastructure/Custom-domains) of the Blaxel Console.
+
+
+## Environment variables and secrets
+
+Pass environment variables to your application through the revision's `envs` field. Each entry supports either a plain `value` or a reference to a Blaxel `secretName`.
+
+```json
+{
+ "spec": {
+ "revisions": [{
+ "image": "my-registry/my-image:latest",
+ "memory": 2048,
+ "envs": [
+ { "name": "DATABASE_URL", "value": "postgres://..." },
+ { "name": "API_KEY", "secretName": "my-api-key-secret" }
+ ]
+ }]
+ }
+}
+```
+
+## Memory and compute
+
+Memory allocation is set per revision in megabytes. The default is 2048 MB. CPU resources are allocated proportionally based on memory (CPU = memory / 2048 cores).
+
+| Memory | CPU cores |
+|--------|-----------|
+| 2048 MB | 1 core |
+| 4096 MB | 2 cores |
+| 8192 MB | 4 cores |
+
+## Application deployment statuses
+
+During the deployment process, the possible application statuses are:
+
+- `DEPLOYING`: The application deployment is in progress.
+- `DEPLOYED`: The application is running and serving traffic.
+- `FAILED`: An error occurred during the build or deployment.
+
+
+
+ Create snapshots and fork sandboxes into applications or new sandboxes.
+
+
+ Manage environment variables and secrets for your deployments.
+
+
diff --git a/Sandboxes/Snapshots-and-fork.mdx b/Sandboxes/Snapshots-and-fork.mdx
new file mode 100644
index 00000000..f2f6b897
--- /dev/null
+++ b/Sandboxes/Snapshots-and-fork.mdx
@@ -0,0 +1,263 @@
+---
+title: 'Snapshots and fork'
+sidebarTitle: 'Snapshots & fork'
+description: 'Create point-in-time snapshots of sandboxes and fork them into new sandboxes or applications.'
+---
+
+Snapshots capture the current state of a sandbox at a point in time. Use snapshots to preserve sandbox state before making changes, or as the basis for forking a sandbox into a new sandbox or [application](/Applications/Overview).
+
+## Create a snapshot
+
+Create a snapshot of an existing sandbox. The snapshot captures the filesystem, running processes, and memory state.
+
+
+
+```typescript TypeScript
+import { SandboxInstance } from "@blaxel/core";
+
+const sandbox = await SandboxInstance.get("my-sandbox");
+const snapshot = await sandbox.createSnapshot({ name: "before-migration" });
+```
+
+```python Python
+from blaxel.core import SandboxInstance
+
+sandbox = await SandboxInstance.get("my-sandbox")
+snapshot = await sandbox.create_snapshot({"name": "before-migration"})
+```
+
+
+
+HTTP API:
+
+```bash
+curl -X POST https://api.blaxel.ai/v0/sandboxes/my-sandbox/snapshots \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{ "name": "before-migration" }'
+```
+
+## List snapshots
+
+
+
+```typescript TypeScript
+import { SandboxInstance } from "@blaxel/core";
+
+const sandbox = await SandboxInstance.get("my-sandbox");
+const snapshots = await sandbox.listSnapshots();
+```
+
+```python Python
+from blaxel.core import SandboxInstance
+
+sandbox = await SandboxInstance.get("my-sandbox")
+snapshots = await sandbox.list_snapshots()
+```
+
+
+
+HTTP API:
+
+```bash
+curl https://api.blaxel.ai/v0/sandboxes/my-sandbox/snapshots \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace"
+```
+
+## Delete a snapshot
+
+```bash
+curl -X DELETE https://api.blaxel.ai/v0/sandboxes/my-sandbox/snapshots/snap_abc123 \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace"
+```
+
+## Fork a sandbox
+
+Forking creates a new resource (sandbox or application) from an existing sandbox. The fork inherits the source sandbox's image, memory configuration, environment variables, and port settings.
+
+### Fork into a new sandbox
+
+
+
+```typescript TypeScript
+import { SandboxInstance } from "@blaxel/core";
+
+const result = await SandboxInstance.fork("my-sandbox", {
+ targetName: "my-sandbox-copy",
+ targetType: "sandbox",
+});
+```
+
+```python Python
+from blaxel.core import SandboxInstance
+
+result = await SandboxInstance.fork("my-sandbox", {
+ "target_name": "my-sandbox-copy",
+ "target_type": "sandbox",
+})
+```
+
+
+
+CLI:
+
+```bash
+bl fork sbx/my-sandbox sbx/my-sandbox-copy
+```
+
+HTTP API:
+
+```bash
+curl -X POST https://api.blaxel.ai/v0/sandboxes/my-sandbox/fork \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "targetType": "sandbox",
+ "targetName": "my-sandbox-copy"
+ }'
+```
+
+### Fork into an application
+
+Create an [application](/Applications/Overview) directly from a running sandbox. The application inherits the sandbox's image, memory, environment variables, and port.
+
+
+
+```typescript TypeScript
+import { SandboxInstance } from "@blaxel/core";
+
+const result = await SandboxInstance.fork("my-sandbox", {
+ targetName: "my-app",
+ targetType: "application",
+ traffic: 100,
+ port: 8080,
+});
+```
+
+```python Python
+from blaxel.core import SandboxInstance
+
+result = await SandboxInstance.fork("my-sandbox", {
+ "target_name": "my-app",
+ "target_type": "application",
+ "traffic": 100,
+ "port": 8080,
+})
+```
+
+
+
+CLI:
+
+```bash
+bl fork sbx/my-sandbox app/my-app --traffic 100 --port 8080
+```
+
+HTTP API:
+
+```bash
+curl -X POST https://api.blaxel.ai/v0/sandboxes/my-sandbox/fork \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "targetType": "application",
+ "targetName": "my-app",
+ "traffic": 100,
+ "port": 8080
+ }'
+```
+
+### Fork with canary traffic
+
+Fork into an existing application as a canary revision receiving a percentage of traffic:
+
+```bash
+bl fork sbx/my-sandbox app/my-app --traffic 20 --port 8080
+```
+
+### Fork with a custom domain
+
+Attach a custom domain to the forked application using the `customDomain` parameter:
+
+
+
+```typescript TypeScript
+import { SandboxInstance } from "@blaxel/core";
+
+const result = await SandboxInstance.fork("my-sandbox", {
+ targetName: "my-app",
+ targetType: "application",
+ traffic: 100,
+ customDomain: "app.example.com",
+});
+```
+
+```python Python
+from blaxel.core import SandboxInstance
+
+result = await SandboxInstance.fork("my-sandbox", {
+ "target_name": "my-app",
+ "target_type": "application",
+ "traffic": 100,
+ "custom_domain": "app.example.com",
+})
+```
+
+
+
+HTTP API:
+
+```bash
+curl -X POST https://api.blaxel.ai/v0/sandboxes/my-sandbox/fork \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "targetType": "application",
+ "targetName": "my-app",
+ "traffic": 100,
+ "customDomain": "app.example.com"
+ }'
+```
+
+### Fork from a snapshot
+
+Use the `snapshotId` parameter to fork from a specific snapshot instead of the current sandbox state:
+
+```bash
+curl -X POST https://api.blaxel.ai/v0/sandboxes/my-sandbox/fork \
+ -H "Authorization: Bearer $BL_API_KEY" \
+ -H "X-Blaxel-Workspace: my-workspace" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "targetType": "application",
+ "targetName": "my-app",
+ "snapshotId": "snap_abc123"
+ }'
+```
+
+## Fork request parameters
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `targetType` | string | Target resource type: `sandbox` or `application` |
+| `targetName` | string | Name of the resource to create or update |
+| `traffic` | integer | Traffic percentage for the new revision (0-100, applications only) |
+| `port` | integer | Port to expose |
+| `customDomain` | string | Custom domain for the application |
+| `prefix` | string | URL prefix for the application |
+| `snapshotId` | string | Fork from a specific snapshot instead of current state |
+
+
+
+ Deploy long-running services with revision management and traffic splitting.
+
+
+ Learn more about sandbox lifecycle and configuration.
+
+
diff --git a/docs.json b/docs.json
index c59f80e8..4f780553 100644
--- a/docs.json
+++ b/docs.json
@@ -66,6 +66,7 @@
},
"Sandboxes/Volumes",
"Sandboxes/Templates",
+ "Sandboxes/Snapshots-and-fork",
"Sandboxes/Schedules",
"Sandboxes/best-practices"
]
@@ -108,6 +109,12 @@
"Jobs/Variables-and-secrets-jobs"
]
},
+ {
+ "group": "Applications",
+ "pages": [
+ "Applications/Overview"
+ ]
+ },
{
"group": "Agents Hosting",
"pages": [