# Connect an AI Agent (MCP)
Source: https://docs.suga.app/agents/mcp
Connect Claude Code, Cursor, and other AI agents to your Suga account over MCP
Suga runs a hosted [Model Context Protocol](https://modelcontextprotocol.io) server that lets an AI agent drive your Suga account the way you would through the dashboard: list projects, edit environment configuration, set variables and secrets, watch deployments, and read logs.
The server lives at a single endpoint:
```
https://dashboard.suga.app/api/mcp
```
It speaks streamable HTTP and authenticates with OAuth, so any MCP client that supports remote servers can connect with just the URL. No API keys to copy or rotate.
## The safety model
The most important thing to understand before you connect an agent: **the agent can prepare changes, but it can never deploy them.**
Every environment in Suga has a **Draft** (a working copy of its configuration) and an **Apply** step that pushes the Draft to running infrastructure. The MCP server has no `apply` or `deploy` tool, and no `delete_project` or `delete_environment` tool, by design. Anything the agent changes about a service, its variables, its volumes, or its scaling lands in the Draft and waits for you.
Four tools act immediately rather than going into the Draft: `create_project`, `create_environment`, `add_custom_domain`, and `remove_custom_domain`. Removing a custom domain takes it out of service straight away.
When an agent makes a change, the tool response includes a **deeplink** back to the affected environment in the Suga UI. You open it, review the rendered diff, and click **Apply** yourself. That visual review is the gate that keeps a misread instruction or a hallucinated container spec from reaching production.
* View your projects, environments, and deployments
* Create projects and environments
* Edit draft configuration: services, volumes, scaling, networking
* Set and remove environment variables and secrets in the draft
* Manage custom domains and connected GitHub repositories
* Read logs, events, and metrics
* Deploy or publish. Configuration changes stay as drafts until you review and apply them yourself
* Read secret values. Secrets are write-only; only names and metadata are ever returned
* Delete projects or environments
The agent acts as **you**: it can only see and touch the organizations you're a member of, and every action is subject to your existing permissions.
## Before you start
* A Suga account. If you don't have one, [sign up](https://dashboard.suga.app/signup) first.
* An MCP client that supports remote servers with OAuth (Claude Code, Cursor, Claude Desktop, and others).
## Connect your agent
Add the server from your terminal:
```bash theme={null}
claude mcp add --transport http suga https://dashboard.suga.app/api/mcp
```
Then start Claude Code and run `/mcp`. Select **suga** and choose **Authenticate** to open the Suga sign-in and approval flow in your browser. Once you approve, the tools are available in your session.
Add Suga to your `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per-project):
```json theme={null}
{
"mcpServers": {
"suga": {
"url": "https://dashboard.suga.app/api/mcp"
}
}
}
```
Open **Cursor Settings → MCP**, find the **suga** server, and click **Login** (or **Needs login**) to complete the OAuth flow in your browser.
Open **Settings → Connectors → Add custom connector**, give it a name (e.g. `Suga`), and paste the URL:
```
https://dashboard.suga.app/api/mcp
```
Save, then click **Connect** and approve access in your browser.
Edit your Codex configuration (`~/.codex/config.toml`) to add the Suga MCP server:
```toml theme={null}
[mcp_servers.suga]
url = "https://dashboard.suga.app/api/mcp"
```
Save, then authenticate with this command:
```bash theme={null}
codex mcp login suga
```
Any client that supports remote MCP servers over streamable HTTP with OAuth can connect. Point it at:
```
https://dashboard.suga.app/api/mcp
```
The server supports OAuth dynamic client registration, so you don't need to pre-register the client or supply a client ID. The OAuth flow starts automatically on first connect.
## Authorize access
The first connection sends you through a browser flow:
You're taken to the Suga login page. Sign in with the same account you use for the dashboard.
A consent screen shows exactly what the connected app can and can't do. Confirm it's the app you're connecting, then approve.
You're redirected back and the connection completes. Your agent can now call Suga tools. You won't need to repeat this unless you disconnect or the session expires.
## A typical workflow
Once connected, you can ask your agent to work on Suga in plain language. A first deployment usually flows like this:
1. The agent creates a project and an environment.
2. It adds a container, either from an image or by connecting a GitHub repository to build from source.
3. It sets any environment variables and secrets the container needs.
4. It hands you a **deeplink**. You open it, review the pending changes, and click **Apply**.
5. The agent watches the deployment and reports back when it's live.
Steps 2 and 3 happen in the Draft. Nothing changes in your running infrastructure until you apply.
## Good to know
* **Secrets are write-only.** An agent can set or rotate a secret, but no tool ever returns a secret's value, only its name and metadata. New values take effect the next time you apply.
* **Building from source needs the GitHub App.** Install the Suga GitHub App from the dashboard first; the agent can't start that install flow itself.
* **Custom domains wait on DNS.** A newly added domain stays pending until you add the DNS records the agent surfaces for it.
## Related
How drafts, deployments, and rollbacks work
Projects, environments, and configuration
Reading logs from your services
Environment variables, secrets, and references
## Need help?
* Join our [Discord community](https://suga.app/chat) for support
* Email us at [support@suga.app](mailto:support@suga.app)
# Suga vs Railway
Source: https://docs.suga.app/comparisons/suga-vs-railway
How Suga Cloud compares to Railway for container deployment
Suga and Railway start from very similar premises. Both run your code as always-on containers rather than serverless functions, both treat Dockerfiles and source builds as first-class inputs, and both support persistent volumes, raw TCP, multi-service applications, and container-based databases.
Because the container side overlaps so heavily, the interesting differences show up around the container rather than inside it: the edge tier in front of it, the regions it can run in, how it's billed, and whose infrastructure it runs on.
Railway runs everything on Railway's own infrastructure, so you pay a flat workspace fee and per-minute compute charges, and you assemble multi-service applications on a visual canvas that wires databases, workers, and crons together, all of which gives you an end-to-end experience on a single provider.
Suga runs on managed infrastructure behind Cloudflare's global edge by default, meters usage as you go, and bundles \$20 of hosting credits into every Pro seat before usage charges accrue. On Enterprise, the same control plane can also target infrastructure you already own on any cloud or on-premises, so one deployment surface can drive the managed environment, workloads running on your existing cloud footprint, or systems already sitting on-prem.
Choosing between them often comes down to a single question about where your infrastructure lives, since a fully managed runtime tied to one provider keeps everything simple and uniform, while a control plane that can also point at your own infrastructure on Enterprise gives you the option to bring your own cluster when that matters.
## How Suga and Railway differ
Both platforms run containers always-on with no cold starts on either side, so the interesting differences show up elsewhere, specifically across the edge tier, the available compute regions, the pricing model, and whether you can run on your own infrastructure.
Railway details are drawn from [Railway's documentation](https://docs.railway.com) and [pricing](https://railway.com/pricing). Competitor capabilities change frequently, so check their current docs before making a decision.
### Compute
| Concern | Railway | Suga Cloud |
| ----------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Runtimes | 11 via Railpack and any via Dockerfile | Any via Dockerfile or auto-detected source builds; Deno for Functions |
| Memory | Up to 32 GB per replica (Pro) | Up to 8 GiB per service on Pro |
| Timeout | No service timeout, 15-min HTTP request max | No execution timeout on the container; HTTP requests typically capped at around 100s by the Cloudflare proxy |
| Scaling | Manual horizontal up to 42 replicas, plus auto vertical | Manual horizontal up to 10 replicas on Pro, plus vertical auto-scaling |
| Container support | Dockerfile and private registries, with SSH access | Dockerfile, auto-detected source builds, and pre-built images from any registry |
| Cold starts | None | None |
| Billing | Per-minute for allocated CPU and RAM | Usage-based metering across compute and storage |
Both platforms run containers always-on and avoid cold starts, but Railway has higher per-replica resource ceilings on the Pro tier, supporting up to 32 GB of memory and 42 replicas compared to Suga's 8 GiB per service and 10 replicas, and Railway also exposes SSH directly into running containers for ad-hoc debugging. Suga meters usage across compute and storage and includes \$20 of hosting credits with every Pro seat that apply before usage charges accrue.
### CDN and Delivery
| Concern | Railway | Suga Cloud |
| ------------------ | ------------------------------------------- | -------------------------------------------------------------- |
| Edge network | 100+ PoPs via Fastly; 4 compute regions | Cloudflare global network (300+ cities); 3 GCP compute regions |
| CDN caching | Static assets only, HTML always from origin | Cloudflare default caching for proxied domains |
| Image optimization | External service needed | Not currently exposed to customers |
| Compression | Not documented | Cloudflare-managed |
Railway uses Fastly to cache static assets, but HTML responses always come back from the origin, which keeps things simple and means HTML rendering happens entirely on Railway's infrastructure on every request. Suga fronts every proxied domain with Cloudflare, so your traffic picks up automatic Brotli and Gzip compression, L3/L4/L7 DDoS protection, and TLS termination at the edge, with application-level caching controlled through the standard HTTP response headers your container emits. On the compute side, Suga currently runs in 3 GCP regions (Americas, Europe, Asia-Pacific) with more on the roadmap, while Railway operates in 4, so the bigger geographic differentiator between the two is what happens at the edge rather than at the origin.
### Security Defaults
| Concern | Railway | Suga Cloud |
| ----------------- | ----------------------------------------- | ---------------------------------------------- |
| DDoS | L3/L4 | L3/L4/L7 via Cloudflare |
| WAF | External provider recommended | Managed WAF, applied by default |
| Bot protection | External provider recommended | Not currently exposed |
| Rate limiting | External provider recommended | Not currently exposed |
| TLS | Automatic | Automatic, with mutual TLS to the origin |
| Compliance | SOC 2 Type II, SOC 3, GDPR; HIPAA BAA | Working toward published certifications |
| Network isolation | Encrypted private networking on all plans | Default-deny network isolation per environment |
Railway's edge security stack is intentionally light, which means for WAF rules, bot protection, and rate limiting you'd integrate an external provider into your traffic path. Suga's traffic flows through Cloudflare's proxy, where DDoS protection and TLS termination apply automatically. A managed WAF is applied by default. Suga maintains the rules, so there is nothing to configure and no custom rules to write today. On compliance, Railway is ahead today with published SOC 2 Type II, SOC 3, GDPR, and a HIPAA BAA available with committed spend, while Suga is working toward those certifications but doesn't publish them yet.
## Compare Suga and Railway features
| Feature | Railway | Suga Cloud |
| ------------------------------ | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| Application hosting | Included | Included on Suga's managed infrastructure, or on infrastructure you already run via BYOC on Enterprise |
| CDN | Fastly, 100+ PoPs, static assets only | Cloudflare global network (300+ cities) |
| Image optimization | External service | Not currently exposed |
| WAF | External provider | Managed WAF, applied by default |
| DDoS protection | L3/L4 | L3/L4/L7 via Cloudflare |
| Bot protection | External provider | Not currently exposed |
| Rate limiting | External provider | Not currently exposed |
| Observability | Resource metrics and log explorer (7–30 day retention) | Pod logs and resource metrics; bring your own APM |
| AI infrastructure | Not offered | Bring your own (LiteLLM template) |
| Databases | Container-based (Postgres, MySQL, Redis, Mongo) | Container-based templates (Postgres, MySQL, MariaDB, Mongo, Redis, MinIO) |
| Private networking | Encrypted private networking, zero-config | Per-environment isolation, default-deny between environments |
| Persistent volumes | Yes | Yes |
| TCP proxy | Yes | Yes |
| Compute regions | 4 | 3 GCP regions (or any region via BYOC on Enterprise) |
| SSH access | Yes | Not currently exposed |
| Run on your own infrastructure | Not offered | Supported on Enterprise (BYOC to any cloud or on-premises) |
| Compliance | SOC 2 Type II, SOC 3, GDPR, HIPAA BAA | Working toward published certifications |
## Choosing between Suga and Railway
| If you need | Choose | Why |
| ------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| L7 DDoS and WAF at the edge | Suga | Cloudflare is on by default; Railway's Fastly tier doesn't include those layers. |
| To run on infrastructure you already own | Suga | Suga's Enterprise plan can deploy workloads onto your own infrastructure on any cloud or on-premises; Railway runs only on Railway. |
| Per-seat pricing with hosting credits bundled in | Suga | Each Pro seat unlocks \$20 in hosting credits before metering kicks in. |
| SSH into running containers | Railway | Railway exposes direct SSH access; Suga uses logs and history-based debugging instead. |
| 32 GB RAM per replica or more than 10 replicas at Pro pricing | Railway | Suga's Pro tier caps at 8 GiB per service and 10 replicas. |
| 7–30 day searchable log retention | Railway | Railway's log explorer retains 7–30 days; Suga streams logs in real time without a persisted archive. |
Choose **Suga** if you want Cloudflare's edge tier included by default (with the option on Enterprise of running on infrastructure you already own on any cloud or on-premises), or choose **Railway** if you need SSH access into running containers, higher per-replica memory ceilings at Pro pricing, or published compliance certifications today.
## Try Suga
* [Sign up for Suga Free](https://dashboard.suga.app/signup)
* [Read the Quickstart](/quickstart)
* [Talk to us](/support/contact) if you're evaluating a migration from Railway
# Suga vs Render
Source: https://docs.suga.app/comparisons/suga-vs-render
How Suga Cloud compares to Render for container deployment
Suga and Render both put the container at the centre of the deployment model, running code as always-on services with Dockerfiles and source builds as first-class inputs, and covering the surrounding pieces most longer-lived workloads need like persistent disks, WebSockets, multi-service topologies, and managed data stores. Because that side lines up so heavily, the interesting differences show up outside the workload itself: the edge in front of it, the geographic reach behind it, how pricing is put together, and whose infrastructure carries the deployment.
Render runs everything on its own infrastructure with a flat monthly workspace fee, per-service compute metered by the second, and a broad catalogue of instance sizes that scales up to 32 GB of RAM and 8 CPU per service.
Suga runs workloads on managed infrastructure fronted by Cloudflare's global edge, meters usage across compute and storage, and drops hosting credits into every Pro seat that draw down before any overage kicks in. Enterprise workspaces unlock a second option: the same control plane can also deploy onto infrastructure you already own on any cloud or on-premises, without switching deployment tooling.
The decision usually turns on where you want your workloads to physically live. Sticking with a single vendor keeps the operating model uniform, while an Enterprise tier that can also target existing infrastructure preserves the option to consolidate under cloud commitments you already run.
## How Suga and Render differ
The tables below step through the four areas where the two platforms genuinely diverge: how the edge in front of the container behaves, which compute regions each covers, how workspace and usage pricing are structured, and whether the workload can run on infrastructure the customer already owns.
Render details are drawn from [Render's documentation](https://render.com/docs) and [pricing](https://render.com/pricing). Competitor capabilities change frequently, so check their current docs before making a decision.
### Compute
| Concern | Render | Suga Cloud |
| ----------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Runtimes | Native runtimes for Node.js/Bun, Python, Ruby, Go, Rust, and Elixir; any via Dockerfile | Any runtime via Dockerfile or auto-detected source builds; Deno for Functions |
| Memory | Up to 32 GB per instance on Pro Ultra | Up to 8 GiB per service on Pro |
| CPU | Up to 8 CPU per instance on Pro Ultra | Up to 4 cores per service on Pro |
| Timeout | Up to 100-minute HTTP request duration | No total-request cap; a 5-minute stream idle timeout closes connections that go silent |
| Scaling | Manual horizontal up to 100 instances; autoscaling on Pro workspace plan and higher | Manual horizontal up to 10 replicas on Pro, plus vertical auto-scaling |
| Container support | Dockerfile, native runtimes, and pre-built images from Docker Hub, GHCR, GitLab CR, Google Artifact Registry, and ECR | Dockerfile, auto-detected source builds, and pre-built images from [most registries](https://docs.suga.app/configure/private-registries#supported-registries) |
| Cold starts | None | None |
| Billing | Flat workspace fee plus per-second compute metering | Usage-based metering across compute and storage |
Render offers a wider set of instance sizes at the top end, scaling up to 32 GB of RAM and 8 CPU per service on Pro Ultra, and it supports up to 100 manually scaled instances against Suga's ten on Pro. On HTTP request lifetimes, Render caps each request at up to 100 minutes as a hard total-duration ceiling, whereas Suga applies no total-request cap but does enforce a 5-minute stream idle timeout, so long streaming or AI workloads that emit data continuously fit naturally on Suga, while requests that need to sit silent for more than five minutes are the ones Render's ceiling is built for.
### CDN and Delivery
| Concern | Render | Suga Cloud |
| ------------------ | ------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| Edge network | Global CDN backed by Cloudflare for static sites; edge caching for paid web services | Cloudflare global network (300+ cities) for proxied domains |
| CDN caching | Static sites globally cached by default; opt-in edge caching for paid web services | Cloudflare default caching for proxied domains |
| Image optimization | Not currently exposed | Not currently exposed |
| Compression | Automatic | Cloudflare-managed |
| Compute regions | 5 (Oregon, Ohio, Virginia, Frankfurt, Singapore) | 3 regions (Americas, Europe, Asia-Pacific) |
Render's static sites are served through a global CDN by default, and paid web services can opt into edge caching that reuses the same network, with cache invalidation on every deploy plus a manual purge from the dashboard. Every proxied Suga domain sits behind Cloudflare's proxy, which handles Brotli and Gzip compression, provides L3/L4/L7 DDoS mitigation, and terminates TLS at the edge, while application-level caching is driven by the `Cache-Control` headers the container returns. At the origin layer, Suga runs in three regions today with additional regions on the roadmap and Render operates in five, keeping the two platforms broadly comparable in origin coverage.
### Security Defaults
| Concern | Render | Suga Cloud |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| DDoS | Free DDoS protection powered by Cloudflare | L3/L4/L7 via Cloudflare |
| WAF | Not exposed as a customer-configurable product | Managed WAF, applied by default |
| Bot protection | Not currently exposed | Not currently exposed |
| Rate limiting | Not currently exposed | Not currently exposed |
| TLS | Automatic (Let's Encrypt and Google Trust Services) | Automatic (Automatic, with mutual TLS to the origin) |
| Compliance | SOC 2 Type 2, ISO 27001, GDPR DPA, HIPAA on Scale plan and above, EU-US DPF | Working toward published certifications |
| Network isolation | Private networking across all plans within a workspace and region; blocking cross-environment traffic requires Pro or above | Default-deny network isolation per environment |
Render provides free DDoS protection powered by Cloudflare on every deployed service, and WAF, bot protection, and rate limiting are not currently exposed as customer-configurable products at the edge. Every request to a Suga service passes through Cloudflare's proxy first, so DDoS mitigation, WAF filtering, and TLS termination apply without any per-service setup. Suga maintains the WAF rules, so there are no custom rules to write today. For teams that need audited compliance, Render currently ships more of the paperwork, holding SOC 2 Type 2, ISO 27001, GDPR DPA, and HIPAA on the Scale plan and above, whereas Suga has those certifications in progress but hasn't published them yet.
### Pricing model
| Concern | Render | Suga Cloud |
| ------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------- |
| Workspace fee | Hobby free; Pro \$25/mo flat; Scale \$499/mo flat; Enterprise custom | Suga Pro per-seat, with \$20 hosting credits per seat |
| Team members | Unlimited on Pro and above | Per-seat |
| Included bandwidth | 5 GB (Hobby), 25 GB (Pro), 1 TB (Scale) then \$0.15/GB overage | Cloudflare-fronted egress metered as part of usage-based billing |
| Autoscaling | Pro workspace plan and above | Included |
| Autoscaling ceiling | Up to 100 instances | Up to 10 replicas on Pro |
| SSO / SCIM | Scale plan and above | Enterprise |
| HIPAA workspace | Scale plan (20% compute uplift, no minimum) | Not currently offered |
Render's pricing model separates a flat workspace fee from per-second compute metering, so once you're on Pro or Scale you invite as many teammates as you want under a single monthly workspace charge, and bandwidth is bundled into each tier with overage billed at \$0.15 per GB. Suga charges per seat and drops \$20 of hosting credits into each Pro seat that offset usage charges before you start paying for compute and storage, which tends to suit smaller teams running production workloads without needing enterprise governance features up front.
## Compare Suga and Render features
| Feature | Render | Suga Cloud |
| ------------------------------ | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Application hosting | Included (Render infrastructure) | Included on Suga's managed infrastructure, or on infrastructure you already run via BYOC on Enterprise |
| CDN | Global CDN for static sites; edge caching for paid web services | Cloudflare global network (300+ cities) |
| Image optimization | Not currently exposed | Not currently exposed |
| WAF | Not currently exposed as a customer product | Managed WAF, applied by default |
| DDoS protection | Free, powered by Cloudflare | L3/L4/L7 via Cloudflare |
| Bot protection | Not currently exposed | Not currently exposed |
| Rate limiting | Not currently exposed | Not currently exposed |
| Observability | Logs, metrics, health checks, per-service dashboards | Pod logs and resource metrics; bring your own APM |
| AI infrastructure | Not offered as a first-party product | Bring your own (LiteLLM template) |
| Databases | Managed Postgres and Key Value (Redis-compatible) | Container-based templates (Postgres, MySQL, MariaDB, Mongo, Redis, MinIO) |
| Private networking | Within a workspace and region on all plans; cross-environment isolation on Pro and above | Per-environment isolation, default-deny between environments |
| Persistent disks | Yes, single-instance only | Yes |
| Public TCP proxy | Not currently exposed | Yes, raw TCP proxying |
| WebSockets | Yes | Yes |
| Compute regions | 5 | 3 regions (or any region via BYOC on Enterprise) |
| Container support | Dockerfile and prebuilt images from 5 supported registries | Dockerfile, auto-detected source builds, and pre-built images from any registry |
| Run on your own infrastructure | Not offered | Supported on Enterprise (BYOC to any cloud or on-premises) |
| Compliance | SOC 2 Type 2, ISO 27001, GDPR DPA, HIPAA on Scale, EU-US DPF | Working toward published certifications |
## Choosing between Suga and Render
| If you need | Choose | Why |
| ------------------------------------------------------------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| DDoS and WAF at the edge | Suga | Cloudflare's proxy applies DDoS protection and a managed WAF by default; Render ships free DDoS protection at the edge, with WAF not currently exposed as a customer product. |
| To run on infrastructure you already own | Suga | Suga's Enterprise plan can deploy workloads onto your own infrastructure on any cloud or on-premises; Render runs only on Render. |
| Per-seat pricing with hosting credits bundled in | Suga | Each Pro seat unlocks \$20 in hosting credits before metering kicks in. |
| Managed Postgres with point-in-time recovery and read replicas | Render | Render's Postgres is fully managed with tiered compute, PITR, and read replicas; Suga ships container-based templates you operate. |
| 32 GB RAM per instance or more than 10 replicas at similar pricing | Render | Render's Pro Ultra tier scales to 32 GB of RAM per instance and up to 100 manually scaled instances; Suga's Pro tier caps at 8 GiB per service and 10 replicas. |
Choose **Suga** when the edge layer sitting in front of your services matters, with the option on Enterprise to keep those services running on infrastructure you already own or are contractually committed to, or choose **Render** when the priorities are higher per-instance memory ceilings, HTTP requests that need to sit idle for many minutes before returning, managed Postgres with point-in-time recovery and read replicas, or published compliance certifications available today.
## Try Suga
* [Sign up for Suga Free](https://dashboard.suga.app/signup)
* [Read the Quickstart](/quickstart)
* [Talk to us](/support/contact) if you're evaluating a migration from Render
# Suga vs Vercel
Source: https://docs.suga.app/comparisons/suga-vs-vercel
How Suga Cloud compares to Vercel for application deployment
Vercel and Suga both help you ship applications to the cloud, but they make very different assumptions about what you're shipping.
Vercel is built around the framework you're using, so when you push code on Next.js, Nuxt, SvelteKit, or one of about thirty others, the platform reads the framework's output and provisions matching infrastructure for you, with ISR caches, edge functions, image optimization, and the AI Gateway all wired in automatically based on what your framework expects.
Suga is built around the container you want to run, so you can push a Dockerfile, point us at a source repository for an auto-detected build, or deploy a pre-built image from any registry, and Suga will run it as an always-on container behind Cloudflare's global edge with persistent volumes, raw TCP, and multi-service private networking available when you need them.
Vercel is a strong fit when you're shipping a web application on a supported framework and you want the platform to handle most of the infrastructure decisions, while Suga is a strong fit when you're shipping containers (backends, workers, multi-service architectures, anything that needs persistent state), with the option on Enterprise to run those containers on infrastructure you already own on any cloud or on-premises.
## How Suga and Vercel differ
Both platforms deploy code to the cloud, but the interesting differences show up across how the runtime works, how the edge tier behaves, how scaling happens, and how billing is structured, which the tables and prose below work through in turn.
Vercel details are drawn from [Vercel's documentation](https://vercel.com/docs) and [pricing](https://vercel.com/pricing). Competitor capabilities change frequently, so check their current docs before making a decision.
### Compute
| Concern | Vercel | Suga Cloud |
| ------------ | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Runtimes | Node.js, Python, Go, Ruby, Rust, Bun | Any via Dockerfile or auto-detected source builds; Deno for Functions |
| Memory | Up to 4 GB per instance | Up to 8 GiB per service on Pro |
| CPU | Up to 2 vCPU | Up to 4 cores per service on Pro |
| Timeout | Up to 800s with Fluid compute | No execution timeout on the container; HTTP requests typically capped at around 100s by the Cloudflare proxy |
| Scaling | Auto to 30,000 concurrent (Pro) | Manual horizontal up to 10 replicas on Pro, plus vertical auto-scaling |
| Build inputs | 37+ frameworks auto-detected, no Dockerfile needed | Dockerfile, auto-detected source builds, or pre-built images from any registry |
| Cold starts | Effectively eliminated | None, since containers are always on |
| Billing | Active CPU time (I/O wait excluded) | Usage-based metering across compute and storage |
Vercel's Fluid Compute model bills only for active CPU time, which is a meaningful advantage for I/O-heavy workloads like model inference or third-party API fan-out where the CPU spends a lot of time waiting on external services. Suga meters the allocated container's usage across compute and storage, which is more predictable for always-on services where the CPU stays busy most of the time, so the right pricing model depends on whether your workload sits idle a lot or works the whole time.
### CDN and Delivery
| Concern | Vercel | Suga Cloud |
| ------------------ | -------------------------------------- | -------------------------------------------------------------- |
| Edge network | 126+ PoPs, 51 countries | Cloudflare global network (300+ cities) for proxied domains |
| CDN caching | Framework-aware (ISR, SWR, Data Cache) | Cloudflare default caching for proxied domains |
| Invalidation | \~300ms global via framework API | Cloudflare TTL behavior; no programmatic cache purge from Suga |
| Image optimization | Built-in (WebP/AVIF, edge-cached) | Not currently exposed to customers |
| Compression | Automatic Brotli + Gzip | Cloudflare-managed |
| Edge key-value | Edge Config (P99 \< 15ms) | Not offered |
Vercel analyzes your framework's output and provisions matching caching primitives for you, including ISR for static-regenerable pages, SWR for data fetching, and the Image API for asset transforms, with cache invalidation programmatic through the framework's API and propagating globally in milliseconds.
Suga keeps caching explicit and container-controlled, so the container you ship goes behind Cloudflare's global edge where Cloudflare's default caching applies alongside whatever `Cache-Control` headers your application emits, which gives you direct control over what gets cached where without giving up the edge entirely, at the cost of framework-aware behaviors like ISR not being derived automatically.
### Security Defaults
| Concern | Vercel | Suga Cloud |
| ----------------- | ------------------------------------------------- | ---------------------------------------------- |
| DDoS | L3/L4/L7 on all plans | L3/L4/L7 via Cloudflare proxy |
| WAF | Custom rules on all plans | Managed WAF, applied by default |
| Bot protection | Managed rulesets + BotID | Not currently exposed |
| Rate limiting | `@vercel/firewall` SDK | Not currently exposed |
| TLS | Automatic | Automatic, with mutual TLS to the origin |
| Compliance | SOC 2 Type 2, ISO 27001, PCI DSS, GDPR; HIPAA BAA | Working toward published certifications |
| Network isolation | Secure Compute with VPC peering (Enterprise) | Default-deny network isolation per environment |
Vercel ships WAF, BotID, and rate limiting as platform primitives that you configure directly in the Vercel dashboard. Suga's edge security comes from the Cloudflare proxy in front of your app, where DDoS protection and TLS termination apply automatically. A managed WAF is applied by default, with rules maintained by Suga rather than written by you. At the cluster layer, every Suga environment is isolated with default-deny network policies, which block lateral movement between environments even if a workload is compromised.
## Compare Suga and Vercel features
| Feature | Vercel | Suga Cloud |
| ------------------------------ | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Application hosting | Included | Included on Suga's managed infrastructure, or on infrastructure you already run via BYOC on Enterprise |
| CDN | Framework-aware, 126+ PoPs | Cloudflare global network (300+ cities) |
| Image optimization | Included | Not currently exposed |
| WAF | Custom rules on all plans | Managed WAF, applied by default |
| DDoS protection | L3/L4/L7 | L3/L4/L7 via Cloudflare |
| Bot protection | Managed rulesets + BotID | Not currently exposed |
| Rate limiting | All plans + SDK | Not currently exposed |
| Observability | Speed Insights, Web Analytics, Log Drains, OTel | Pod logs and resource metrics |
| AI infrastructure | AI Gateway, AI SDK, Sandbox, Agent | Bring your own |
| Databases | Managed providers via Marketplace | Container-based templates (Postgres, MySQL, MariaDB, Mongo, Redis, MinIO) |
| Private networking | Secure Compute with VPC peering (Enterprise) | Per-environment isolation, default-deny between environments |
| Persistent volumes | Not supported | Yes |
| TCP proxy | Not supported | Yes, raw TCP proxying |
| Docker support | Not supported | Yes |
| Multi-service architectures | Single project model | Multiple computes per environment with internal service discovery |
| Preview environments | Per-branch URL, zero cost | Manual environment creation |
| Run on your own infrastructure | Not supported | Supported on Enterprise (BYOC to any cloud or on-premises) |
## Choosing between Suga and Vercel
| If you need | Choose | Why |
| --------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| Framework-aware caching, edge SSR, image optimization | Vercel | ISR, SWR, the Image API, and middleware are wired up automatically from your framework's output. |
| AI Gateway, AI SDK, or sandboxed code execution | Vercel | Vercel includes these primitives natively; Suga is a deployment substrate without them. |
| Active-CPU pricing for I/O-heavy workloads | Vercel | Vercel excludes I/O wait time from billing, which favors workloads with significant external waits. |
| Always-on containers, persistent volumes, or raw TCP | Suga | Suga supports first-class container deployments with state and direct TCP access. |
| Multi-service backends with private networking | Suga | Suga deploys multiple computes per environment with internal service discovery between them. |
| To run on infrastructure you already own | Suga | Suga's Enterprise plan can deploy workloads onto your own infrastructure on any cloud or on-premises; Vercel runs only on Vercel. |
| Container-based databases (Postgres, MySQL, Redis, Mongo) | Suga | Suga ships container templates that run inside your environment. |
Choose **Vercel** if you're shipping a web application on a supported framework and you want infrastructure derived automatically from the framework's output, or choose **Suga** if you're shipping containers (backends, workers, multi-service architectures, anything with persistent state), with the option on Enterprise to run those containers on infrastructure you already own.
## Try Suga
* [Sign up for Suga Free](https://dashboard.suga.app/signup)
* [Read the Quickstart](/quickstart)
* [Talk to us](/support/contact) if you're evaluating a migration from Vercel
# Environments
Source: https://docs.suga.app/concepts/environments
Isolated deployment targets for different stages of development
Environments are isolated deployment targets within a project. Run multiple versions of your application simultaneously—production, staging, development—without them interfering with each other.
Each environment maintains its own deployment history with full audit trails and rollback capability.
## What is an Environment?
An environment is an isolated namespace where you deploy your application:
* **Isolated Infrastructure** - Each environment has its own services, volumes, and configuration
* **Separate Secrets** - Environment variables don't leak between environments
* **Independent Scaling** - Production can have 5 replicas while dev has 1
* **Version Control** - Full deployment history with rollback to any previous state
Every project starts with a default **production** environment. Create additional environments as needed.
## Common Environment Types
| Environment | Purpose | Typical Configuration |
| --------------- | ---------------------- | -------------------------- |
| **production** | Live customer-facing | High resources, redundancy |
| **staging** | Pre-production testing | Production-like, test data |
| **development** | Active feature work | Minimal resources |
## Creating an Environment
From the environment dropdown in the top bar:
1. Click **New Environment**
2. Enter an environment name
3. Under **Starting point**, choose **Clone from existing** (and pick the source environment) or **Empty environment**
4. Click **Create**, then apply when you're ready to deploy
Free plans are limited to 1 environment across the whole organization. Pro and Enterprise plans have no limit.
## Environment Isolation
Each environment is completely isolated:
**Separate Namespaces:**
* Services in "production" cannot communicate with services in "staging"
* Private networking only works within the same environment
**Independent Configuration:**
* Different environment variables per environment
* Different secrets (database passwords, API keys)
* Different resource allocations (CPU, memory, replicas)
**Separate Deployments:**
* Deploy to production without affecting staging
* Each environment has its own deployment history
* Rollback independently per environment
## Cloning an Environment
**Clone from existing** creates a complete, isolated copy of your infrastructure. All services, configuration, and volume definitions are duplicated to a new environment where you can experiment safely.
### What Gets Copied
**Copied:**
* All services (containers and functions) with their images
* Resource allocations (CPU, memory, replicas)
* Networking configuration (HTTPS endpoints, TCP proxies)
* Volume definitions and mount paths
* Service connections and dependencies
* Environment variables, including their values
**Not copied:**
* Volume data (volumes are created empty)
* Deployment history (starts fresh)
* Logs and metrics
### The Variable Review Step
After you name the environment and pick a source, Suga shows every variable it found, grouped by service. Each one has a checkbox and an editable value, so you can drop or change anything before the environment is created.
Variables marked sensitive, and values Suga detects as secrets, start **unchecked**. Everything else starts checked. Tick a sensitive variable to carry its value over, or leave it off and set a fresh value later.
### After Cloning
1. **Fill in any variables you skipped** - Set passwords, API keys, and other secrets you chose not to copy.
2. **Apply** - The new environment starts undeployed. Click **Apply** to provision infrastructure.
3. **Populate Data** - Volumes are empty. Load data from backups or seed manually if needed.
### Clone vs. Empty
**Clone when:**
* Testing changes to existing infrastructure
* You need environment parity, such as staging matching production
* Debugging issues that require exact replication
**Start empty when:**
* Starting a new architecture from scratch
* Existing environments don't match what you need
* Experimenting with a completely different setup
Cloning captures every detail: image tags, resource limits, volume sizes, networking. Nothing is missed or approximated.
## Switching Environments
1. Click the environment dropdown in the top-right
2. Select the environment
3. The canvas updates to show that environment's infrastructure
## Deleting Environments
Use the environment selector to switch to the target environment.
Open the environment dropdown in the top bar, choose **Delete Environment**, and confirm.
Deleting permanently removes all services, volumes, deployments, and data. It cannot be undone, and it works on any environment, including production.
## Common Questions
No, environments are isolated. Private networking only works within the same environment. For cross-environment communication, use public networking (HTTPS/TCP).
Yes. Cloning captures configuration, not running state, and it is instant.
No, volumes are created empty. Load data from backups or seed manually if needed.
Yes. Each environment can use different image tags (e.g., production uses `v1.0.0` while staging uses `v1.1.0-beta`).
No, cloning only works within the same project.
Environment merging is planned for a future release. For now, apply changes from the cloned environment to the original by hand.
# Organizations
Source: https://docs.suga.app/concepts/organizations
Team workspaces, member management, and access control
Organizations are the top-level entity in Suga. They serve as team workspaces where you manage projects, collaborate with team members, and handle billing.
## What is an Organization?
An organization represents your team or company:
* **Team Workspace** - Shared space for all team projects
* **Billing Entity** - Subscription and payment handled at org level
* **Access Control** - Invite members and assign roles
* **Audit Trail** - Every deployment tracked with who, when, and what
Every Suga account starts with a personal organization. You can create additional organizations for teams or clients.
## Organization Structure
```mermaid theme={null}
graph TD
org[Organization: Acme Corp]
org --> members[Members
5 users]
org --> projects[Projects
8 active]
org --> billing[Billing
Pro Plan]
```
## Creating an Organization
Click the organization dropdown in the top-left corner.
Select **New Organization** and enter a name.
## Roles and Permissions
Suga uses role-based access control with three built-in roles:
| Role | Description |
| ---------- | --------------------------------------------------------- |
| **Owner** | Full control, including billing and removing other owners |
| **Admin** | Manage projects, team, and billing, cannot remove owners |
| **Member** | Create and deploy, view team |
Roles are set at the organization level and apply to all projects.
### Permissions Matrix
| Permission | Owner | Admin | Member |
| --------------------------- | :---: | :-------: | :----: |
| **Projects & Environments** | | | |
| View projects/environments | ✅ | ✅ | ✅ |
| Create/edit projects | ✅ | ✅ | ✅ |
| Delete projects | ✅ | ✅ | ✅ |
| **Deployments** | | | |
| View deployments | ✅ | ✅ | ✅ |
| Deploy/rollback | ✅ | ✅ | ✅ |
| **Team Management** | | | |
| View members | ✅ | ✅ | ✅ |
| Invite/remove members | ✅ | ✅ | ❌ |
| Change roles | ✅ | Non-Owner | ❌ |
| **Organization** | | | |
| Edit org settings | ✅ | ✅ | ❌ |
| **Billing** | | | |
| Manage subscription | ✅ | ✅ | ❌ |
| View invoices | ✅ | ✅ | ❌ |
### Role Guidelines
**Owner** - Keep to 1-3 people (founders, CTO). Can make irreversible changes, including removing other owners.
**Admin** - Senior engineers and team leads who need full project access.
**Member** - Default role for developers. Can build and deploy but cannot manage the team.
## Inviting Team Members
Click **Members** in the left sidebar.
Enter email address and select role.
They receive an email invitation and gain access upon accepting.
Invited members don't count toward your seat limit until they accept.
## Removing Team Members
When someone leaves the team:
Go to **Members** in the left sidebar, click the "..." menu next to the person, and choose **Remove**.
If they had production access, rotate:
* Database passwords
* API keys
* Registry credentials
Seat count decreases immediately and billing adjusts at the next cycle.
## Changing Roles
Owners can change anyone's role. Admins can change Member and Admin roles (not Owners).
1. Go to **Members** in the left sidebar
2. Find the member
3. Click the "..." menu, choose **Change Role**, and pick the new role
4. Changes take effect immediately
## Billing
Pro plan uses seat-based pricing (\$20/user/month):
* Each team member with any role counts as one seat
* Owners, Admins, and Members all count equally
* Billed monthly based on active seats
**Plan limits:** Member count, project count, compute, memory, storage, and replica caps all vary by tier. See [Plan Limits](/reference/limits) for the full breakdown, and [suga.app/pricing](https://www.suga.app/pricing) for current pricing.
## Organization Navigation
Organization pages live in the left sidebar:
* **Projects** - Every project in the organization
* **GitHub Integration** - Manage the Suga GitHub App and repository access
* **Usage** - Resource usage and costs for the current period
* **Members** - Invite, manage, and remove team members
* **Billing** - Subscription, invoices, and payment method
* **Cluster** - Cluster connection, shown only when you bring your own cluster
* **Organization Settings** - Organization name and other details
## Handing Over Ownership
There is no one-click ownership transfer. Hand over ownership in two steps:
Go to **Members**, open the "..." menu next to the person, choose **Change Role**, and set them to **Owner**.
From your own row in **Members**, open the "..." menu and choose **Leave Organization**, or ask the new Owner to change your role to Admin or Member.
An organization must always have at least one Owner, so promote the new Owner before you leave. Suga blocks the last Owner from leaving.
## Common Questions
Yes. Switch between them using the dropdown in the top-left corner.
Not from the dashboard. Email [support@suga.app](mailto:support@suga.app) and we'll do it for you. Deletion permanently removes all projects, environments, deployments, and data, and it cannot be undone.
Yes, currently there are no per-project permissions. All members can access all projects within the organization. Enterprise custom permissions are coming soon.
# Overview
Source: https://docs.suga.app/concepts/overview
Understanding Suga's architecture and fundamental building blocks
This section introduces the core concepts that make up Suga's architecture. Understanding these concepts will help you design and manage applications effectively.
## Hierarchy
Suga organizes infrastructure in a clear hierarchy:
```mermaid theme={null}
graph TD
A[Organization] --> B[Projects]
B --> C[Environments]
C --> D[Deployments]
D --> E[Services
Containers or Functions]
D --> F[Volumes
Persistent Storage]
```
### The Mental Model
Think of Suga as **applications, not servers**:
* You design what you want to run (services and volumes)
* You don't manage where or how it runs
* You focus on configuration and connections
* Suga handles provisioning, networking, and orchestration
Kubernetes powers Suga under the hood, but you never need to learn Kubernetes concepts or YAML files.
## Key Concepts at a Glance
| Concept | Description | Example |
| ---------------- | ------------------------------------------------- | --------------------------- |
| **Organization** | Team workspace and billing entity | "Acme Corp" |
| **Project** | Application container | "Marketing Website" |
| **Environment** | Isolated deployment target | "production", "staging" |
| **Deployment** | Immutable snapshot of infrastructure | "Deploy #42 on Jan 28" |
| **Service** | Running workload (Container or Function) | "api", "frontend", "worker" |
| **Volume** | Persistent block storage | "postgres-data" (5 GB) |
| **Networking** | Public (HTTPS/TCP) or private (service discovery) | HTTPS domain or TCP proxy |
## Organizations
Organizations are team workspaces:
* The top-level entity in Suga
* Billing and subscription management
* Team member invitations and roles
* Own multiple projects
[Learn more about Organizations →](/concepts/organizations)
## Projects
Projects are application containers:
* Belong to one organization
* Have a display name you can change at any time, which does not have to be unique
* Are addressed by an internal ID, so renaming a project never changes its URL
* Contain multiple environments
[Learn more about Projects →](/concepts/projects)
## Environments
Environments are isolated deployment targets:
* Separate namespaces for production, staging, development
* Each has its own services and volumes
* Independent configuration and secrets
* Share the same project structure
Preview Environments (automatic PR environments) are coming soon in a future release.
[Learn more about Environments →](/concepts/environments)
## Deployments
Deployments are immutable snapshots:
* Capture complete infrastructure state at a point in time
* Include all services, volumes, configuration, and networking
* Tracked in deployment history for rollback
* Only one deployment is active per environment
[Learn more about Deployments →](/operate/deployments)
## Services
Services are your running workloads:
**Docker-based service:**
* Run any Docker image
* Support for public and private registries
* Configure commands and ports
* Best for existing applications and standard workloads
**Serverless-style service:**
* Write Deno/TypeScript code directly in Suga
* Built-in code editor, no Docker build needed
* Ideal for APIs and lightweight services
* Automatically scaled and managed
All services support:
* Environment variables with secrets encryption
* Resource limits (CPU and memory)
* Horizontal scaling with replicas
* Public networking (HTTPS/TCP) and private networking (service discovery)
[Learn more about Services →](/concepts/services)
## Volumes
Volumes provide persistent storage:
* Block storage that survives restarts and redeployments
* Size limits vary by plan (check dashboard for current limits)
* Mount to services at specified paths
* Essential for databases and stateful applications
Volumes can only be mounted to one service at a time, and that service must have exactly 1 replica.
[Learn more about Storage →](/configure/volumes)
## Networking
Suga offers two networking modes:
**Private Networking (Service Discovery):**
* Automatic DNS-based discovery
* Services communicate using service names
* Format: `service-name:port`
* Example: `postgres:5432`, `redis:6379`
**Public Networking:**
* **HTTPS Endpoints** - Port 443 with automatic TLS and domains
* **TCP Proxy** - Non-HTTP protocols like PostgreSQL or SSH
* Automatic load balancing across replicas
[Learn more about Networking →](/configure/networking)
## Templates
Templates are pre-configured project resources:
* Vetted configurations for common services
* Auto-fill images, ports, volumes, and environment variables
* Available for databases, frameworks, and tools
* Save time with best-practice defaults
[Learn more about Configuration →](/reference/configuration)
## Next Steps
Explore each concept in depth:
Team workspaces and billing
Application containers
Isolated deployment targets
Immutable infrastructure snapshots
Containers and functions
Public and private networking
Persistent storage
Templates and settings
# Projects
Source: https://docs.suga.app/concepts/projects
Services, environments, and infrastructure for your application
Projects are the primary organizational unit in Suga. Each project represents a complete application with all its services, databases, and infrastructure.
## Key Features of a Project
A project contains your application:
* **Logical Boundary** - Groups related services and infrastructure
* **Multiple Environments** - Each project has production, staging, dev, etc.
* **Canvas Workspace** - Visual design space for your infrastructure
* **Deployment History** - Complete record of infrastructure changes per project
* **Version Control** - Every change tracked with commit messages and author
Think of a project as one complete application, like "Marketing Website", "E-commerce API", or "Internal Dashboard".
## Project Structure
```mermaid theme={null}
graph TD
project[Project: E-commerce API]
project --> envs[Environments]
envs --> prod[production]
envs --> staging[staging]
envs --> dev[development]
project --> infra[Infrastructure per environment]
infra --> services[Services: api, worker, postgres, redis]
infra --> volumes[Volumes: postgres-data 5 GB]
```
## Creating a Project
Click **New project** in the dashboard to open the New Project page, which offers three ways to start. Whichever you pick, the project is created with a default `production` environment and full deployment tracking, and the canvas opens.
### Import from a GitHub repository
Click **Connect GitHub** to install the Suga GitHub App on your account or organization (once per account or org), then pick the repository you want to deploy. Suga takes you to an import page where you set the project name and the build and deploy settings:
* **Branch** - the branch Suga watches and builds from
* **Build method** - auto-detect, or point Suga at your Dockerfile
* **Root directory** - for monorepos, the subdirectory holding the app
* **Build args** - values passed to the build
Click **Create project**. The project opens on the canvas with a container already connected to the repository. See [Build from GitHub](/concepts/services#build-from-github) for how rebuilds work after that.
### Start from a template
Under **Starting from scratch?**, pick a template such as PostgreSQL, Redis, MySQL, or MongoDB. Suga creates the project with that service configured and ready on the canvas. Templates are single services, so add the rest of your infrastructure from the canvas afterwards.
### Start with an empty project
Click **Create empty project** for a blank canvas. Use this when you're importing a Compose file, adding a function, or bringing a pre-built image from a registry.
## Project Settings
Access project settings from the project dropdown menu. Settings are minimal and focused on project identity:
### General
* **Project Name** - Change the display name shown in the dashboard
* **Description** - Optional description for the project
### Delete Project
Permanently delete the project and all its data. This action is in the danger zone section at the bottom of settings.
Deleting a project permanently deletes all environments, deployments, services, volumes, and data. This action cannot be undone.
## The Canvas
Every project has a visual canvas where you design infrastructure:
**Canvas Features:**
* Add services, volumes, and templates to your infrastructure
* Visual connections between services and volumes
* Real-time configuration panel
* Environment selector to switch between production/staging/dev
* Deploy button to push changes live
## Environments
Each project can have multiple environments (production, staging, development, preview, etc.) with isolated namespaces and independent configuration. See [Environments](/concepts/environments) for detailed information.
## Common Questions
Yes, you can change the project name anytime in Project Settings.
Not currently. You'll need to recreate the project in the target organization. Export your configuration from the canvas first.
There's no hard limit on services per project. Resource availability depends on your plan.
All deployments are immediately stopped and all data is permanently deleted. Make sure to back up any important data before deleting a project.
# Services
Source: https://docs.suga.app/concepts/services
Running workloads - containers and functions
Services are the building blocks of your application. They represent running workloads that handle requests, process data, serve web pages, or perform background jobs.
## What is a Service?
A service is a running instance of your application code:
* **Execution Environment** - Where your code runs
* **Configurable Resources** - CPU, memory, and replicas
* **Network Accessible** - Public (HTTPS/TCP) or private (service discovery)
* **Stateless** - Use volumes for persistent storage
Suga supports two types: **Containers** and **Functions**.
## Containers vs. Functions
| Feature | Container | Function |
| ----------------- | ---------------------------- | -------------------------- |
| **Runtime** | Any (Docker) | Deno only |
| **Language** | Any | TypeScript/JavaScript |
| **Configuration** | Image + tag | Code in editor |
| **Setup** | Docker build externally | Write code directly |
| **Flexibility** | High | Simple and fast |
| **Best For** | Full applications, databases | APIs, webhooks, prototypes |
***
## Containers
Containers run Docker images from any registry. They provide maximum flexibility for existing applications in any language or framework.
A container's image comes from one of two sources:
* **Build from GitHub** - Connect a repository so Suga builds the image for you. Each push to the watched branch triggers an automatic rebuild and redeploy.
* **Pre-built Image** - Pull an existing image from any Docker registry. Best when you already build elsewhere (CI, local Docker, another platform) or are running off-the-shelf images like databases, caches, etc.
### Build from GitHub
Connect a GitHub repository and Suga builds the image for you. Pushes to the watched branch trigger an automatic rebuild and redeploy.
In the container's Image section, choose **Build from GitHub** and install the Suga GitHub App on your account or organization. Grant access to the repositories you want to build from.
Pick a repository and the branch to watch. Pushes to this branch trigger a new build.
* **Dockerfile** - point Suga at a `Dockerfile` in the repo.
* **Auto-detect** - leave the Dockerfile field empty and Suga reads the repo to generate a build. Works for most Node.js, Python, Go, Ruby, Rust, Java, and PHP projects.
Click **Apply** to build the image and roll out the service. Subsequent pushes to the watched branch trigger an automatic rebuild and redeploy.
The Suga GitHub App is installed once per account or organization. After installation, any container service can build from the repositories you've granted access to.
Use a release branch (e.g. `main` or `release`) for production environments and a development branch for staging. Each environment can watch a different branch of the same repo.
#### Build Configuration
Dockerfile builds expose four settings:
| Setting | Default | Purpose |
| ------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Dockerfile path** | `Dockerfile` | Path to the Dockerfile, relative to the repo root. Set this when your Dockerfile lives in a subdirectory (e.g. `apps/api/Dockerfile`). |
| **Build context** | `.` (repo root) | Directory sent as build context. Narrow it to a sub-path (e.g. `apps/api`) in monorepos. |
| **Target stage** | *(final stage)* | For multi-stage Dockerfiles, build up to a named `FROM ... AS ` target. |
| **Build args** | *(none)* | Key/value pairs passed as `--build-arg`, available at build time. |
Branch and build configuration together identify a build, so two services on the same repo can build different stages or contexts without colliding.
#### Auto-Build on Push
Auto-build is on by default. Each push to the watched branch:
1. Builds the configured Dockerfile (or the auto-detected project).
2. Tags the image with the commit SHA.
3. Rolls out the new image to every environment whose service is wired to that branch.
Suga deduplicates by commit SHA and build configuration, so the same commit doesn't rebuild twice. Changing only env vars or resource sizing redeploys without a rebuild.
Turn off auto-build on the service to pause this. Manual builds from the dashboard still work.
### Pre-built Image
Pull an image from any Docker-compatible registry (Docker Hub, GHCR, GCR, ECR, ACR, or self-hosted) by its full reference:
```
[registry/]repository:tag
```
Examples:
* `nginx:alpine` - Official Nginx from Docker Hub
* `postgres:16-alpine` - PostgreSQL 16
* `ghcr.io/username/myapp:v1.0.0` - GitHub Container Registry
**Command** (Optional) - Override the container's default entrypoint.
**Ports** - Which ports your application listens on inside the container.
For private registries, attach credentials to the service. See [Private Registries](/configure/private-registries).
#### Automatic Updates from External Registries
After a pre-built image is deployed, Suga polls the registry for a new digest at the same tag and rolls the service forward when one appears. Useful for:
* Mutable tags like `:latest`, `:stable`, or `:edge`.
* External CI pipelines that build outside Suga and push to a tag your service tracks.
Images Suga builds itself don't wait on the poll — the build triggers the rollout directly when it finishes.
Pin to a specific version tag (e.g. `myapp:v1.2.3`) instead of `:latest` if you want the service to roll out only when you bump the tag.
### Creating a Container
Click **Add** in the top right of the canvas, or right-click empty space. The palette is searchable and lists **Service from GitHub**, **Service from Container**, **Template**, **Function**, and **Import Compose**.
Choose **Service from GitHub** to [build from source](#build-from-github), **Service from Container** for a [pre-built image](#pre-built-image) from a registry, or **Template** for a pre-configured service. Then set the display name.
If your app listens on a port, specify it. Enable HTTPS or TCP proxy for public access.
Database URLs, API keys (mark as Sensitive), feature flags.
Allocate CPU and memory. New services start at 0.1 CPU and 128 MiB.
Click **Apply** to provision the container.
### Supported Registries
**Public (no credentials):**
* Docker Hub: `nginx`, `postgres`, `redis`
* GitHub Container Registry: `ghcr.io/username/image`
* Quay.io: `quay.io/organization/image`
**Private (with credentials):**
* Docker Hub, GHCR, GCR, ECR, ACR, self-hosted
Enter credentials in the **Service from Container** dialog (or the service's **Config** tab for an existing service), under **Registry credentials**. See [Private Registries](/configure/private-registries) for setup.
Suga runs on Linux AMD64. If building on Apple Silicon, use `--platform linux/amd64`.
### Docker Compose Import
Import existing Docker Compose files:
1. Open the Add palette and choose **Import Compose**
2. Paste YAML or upload file
3. Review parsed services
4. Import to canvas
**Supported:** Services, images, env vars, ports, named volumes, resource limits.
**Not supported:** Build contexts (use pre-built images), bind mounts, health checks.
***
## Functions
Functions run Deno code. Write TypeScript/JavaScript directly in the dashboard instead of building Docker images.
### How Functions Work
Functions start an HTTP server on a configured port. Configuration (env vars, resources, networking, replicas) is identical to containers, but you write code in the **Code** tab instead of specifying an image.
There's no container build for functions. Your TypeScript ships with the deployment and runs on a managed Deno runtime, so changes go live in seconds. That makes functions a good fit for small APIs, webhooks, and quick prototyping.
### Default Template
New functions use this Hono-based template:
```typescript theme={null}
import { Hono } from "npm:hono@^4";
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";
const app = new Hono();
app.get("/", (c) => {
return c.json({ message: "Hello from Deno function!" });
});
const port = parseInt(Deno.env.get("PORT") || "8080");
console.log(`Server running on port ${port}`);
serve(app.fetch, { port });
```
Your code must start an HTTP server on the configured port (default 8080).
### Code Editor
Select function → **Code** tab → write code → **Apply**.
The editor supports TypeScript syntax highlighting and basic completion.
### Imports
```typescript theme={null}
// npm packages
import { Hono } from "npm:hono@^4";
// Deno standard library
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";
// Third-party modules
import { Client } from "https://deno.land/x/postgres@v0.17.0/mod.ts";
```
### Environment Variables
```typescript theme={null}
const dbUrl = Deno.env.get("DATABASE_URL");
const apiKey = Deno.env.get("API_KEY");
```
Configure in the Config tab. Mark sensitive values as Sensitive.
***
## Common Configuration
Both containers and functions share these configuration options:
### Resources
Each service is configured with CPU, memory, and replicas. Your allocation is a guaranteed floor, not a cap: services can burst above it for free, and billing is based on the allocation. See [Billing and Resource Allocation](/reference/billing) for how that works and how to size a service, and [Plan Limits](/reference/limits) for tier maximums, resource pools, volume limits, and the CPU/memory ratio rules.
### Networking
**Private** - Services in the same environment communicate via service names:
```
http://api:3000
postgres:5432
```
**Public HTTPS** - Web traffic with automatic TLS through Cloudflare.
**Public TCP** - Non-HTTP protocols (databases, SSH, custom protocols).
See [Networking](/configure/networking) for details.
### Environment Variables
Key-value configuration for your services:
* Database connection strings
* API keys and secrets (mark as Sensitive)
* Feature flags and settings
### Volumes
Persistent storage that survives restarts and redeployments:
* Mount paths inside the container
* Size limits vary by plan
* Single-mount only (one service per volume)
See [Storage Reference](/configure/volumes) for details.
## Service Templates
Templates provide pre-configured services for common use cases:
* **PostgreSQL** - Database with volume and default credentials
* **Redis** - Cache with persistence options
* **MariaDB** - MySQL-compatible database
Templates auto-generate secure passwords and configure networking.
# Custom Domains
Source: https://docs.suga.app/configure/custom-domains
Use your own domain names with Suga services
Custom domains let you serve your Suga services from your own domain (e.g., `app.example.com`) instead of the auto-generated Suga domains.
## How It Works
When you add a custom domain to a service, Suga provides the DNS records you need to configure with your DNS provider. Once the records are in place, Suga automatically verifies ownership and provisions TLS certificates. No manual certificate management required.
**What you get:**
* Automatic TLS certificates
* Cloudflare CDN, WAF, and DDoS protection
* Zero-downtime certificate renewals
## Adding a Custom Domain
Click on the service you want to assign a custom domain to.
In the properties panel, open the **Config** tab.
In the **Public Networking** section, click **+ Custom Domain**. Enter your domain name (e.g., `app.example.com`) and the target port your application listens on (e.g., `3000`).
Suga will display the DNS records you need to add. Create a **CNAME** record with your DNS provider pointing your domain to the target Suga shows you.
Example:
| Type | Name | Target |
| ----- | ----- | ------------------------------------------------------------- |
| CNAME | `app` | `a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4.cname.us-central1.suga.run` |
Copy the target from the UI. It contains a hash of your environment, so you cannot work it out yourself, and it is different for every environment.
Click **Apply**.
Once your DNS records propagate, Suga automatically verifies your domain and provisions a TLS certificate. This typically takes a few minutes.
DNS verification must complete within **48 hours** of adding the domain. If your DNS records aren't detected in that time, the claim will expire and you'll need to re-add the domain to start a new verification.
Your service will then be accessible at your custom domain.
## Apex Domains
Apex (root) domains like `example.com` (without a subdomain prefix) require special DNS support because the DNS specification doesn't allow CNAME records at the zone apex.
Your DNS provider must support **CNAME flattening**, **ANAME**, or **ALIAS** records to use an apex domain. Not all providers support this.
### Supported DNS Providers
Providers that support CNAME flattening or equivalent include:
| Provider | Mechanism |
| ------------------------------ | ------------------------------------- |
| **Cloudflare** | CNAME flattening (automatic for apex) |
| **NS1** | ANAME records |
| **DNSimple** | ALIAS records |
| **Constellix / DNS Made Easy** | ANAME records |
| **EasyDNS** | ALIAS records |
| **DigitalOcean DNS** | ALIAS records (CNAME flattening) |
| **Namecheap** | ALIAS records |
| **Netlify DNS** | ALIAS records |
**AWS Route 53** and **Azure DNS** support ALIAS records, but only for pointing to their own services. They do not support arbitrary external targets. These will **not** work for Suga custom domains.
Some traditional registrar DNS providers (e.g., GoDaddy) do not support any of these mechanisms. You'll need to either switch to a supported provider or use a subdomain instead.
Check your DNS provider's documentation if you're unsure whether they support this.
### Configuring an Apex Domain
When you add an apex domain, Suga will provide two DNS records:
| Type | Name | Target / Value |
| ----- | -------------------------- | ------------------------------------------------------------- |
| CNAME | `example.com` | `a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4.cname.us-central1.suga.run` |
| TXT | `_suga-verify.example.com` | `suga-verify=a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4` |
Note the TXT record's name: it goes on the `_suga-verify` subdomain, not on the apex itself. Copy both records from the UI rather than typing them from this page.
1. Add both the **CNAME** (or ALIAS/ANAME equivalent) and the **TXT** record with your DNS provider
2. Wait for DNS propagation and automatic verification
3. Apply your changes
If your DNS provider doesn't support CNAME flattening, you can use a subdomain like `www.example.com` or `app.example.com` and redirect to it from the apex domain.
## Domains Already Using Cloudflare
If your domain is already on Cloudflare, you'll need to adjust the proxy setting for the CNAME record that points to Suga.
Cloudflare's proxy (orange cloud) must be **disabled** for the CNAME record pointing to Suga. Set the record to **DNS only** (grey cloud). Suga cannot verify your domain while the Cloudflare proxy is enabled, because it hides the underlying CNAME target.
Suga provides its own Cloudflare CDN, WAF, and DDoS protection for custom domains, so disabling the proxy on your side does not reduce protection, your traffic is still routed through Cloudflare's edge network via Suga.
## Domain Conflicts
A domain can only be active on one Suga environment at a time. If another organization has already verified and activated the same domain, you'll receive an error when trying to add it.
Unverified (pending) claims from other organizations do not block you, only proven ownership counts. If you need to move a domain between environments within your organization, remove it from the original environment first, then add it to the new one.
## Common Questions
Usually a few minutes, but DNS propagation can take up to 48 hours depending on your provider and TTL settings. If verification doesn't complete within 48 hours, the claim expires and you'll need to re-add the domain.
Yes. Add each domain separately through the Public Networking configuration.
No. Suga automatically provisions and renews SSL/TLS certificates for all custom domains.
Yes. The auto-generated Suga domain continues to work alongside your custom domain.
Standard DNS does not allow CNAME records at the zone apex. Your provider needs to support CNAME flattening, ANAME, or ALIAS records. If it doesn't, use a subdomain like `www.example.com` with a redirect instead.
Make sure the CNAME record pointing to Suga has the Cloudflare proxy **disabled** (grey cloud / DNS only). Suga can't verify the CNAME target while it's hidden behind Cloudflare's proxy.
## Next Steps
Learn about HTTPS endpoints, TCP proxy, and private networking
How Cloudflare's edge and Suga regions route traffic
Configure environment variables, resources, and scaling
# Environment Variables
Source: https://docs.suga.app/configure/environment-variables
Set values on a service, mark secrets, and reference values from other services
Environment variables configure a service without changing its image. Suga keeps them per service, per environment, so the same image can run with different settings in staging and production.
## Adding a Variable
Select the service on the canvas, then open the **Env Vars** tab.
Click **Edit environment variables**. Add a key and a value for each variable.
Keys are usually uppercase with underscores, like `DATABASE_URL`.
**Save** records your changes on the canvas. They do not reach the running
service until you click **Apply** and the environment is deployed.
To bring in many variables at once, click **Import** in the dialog and choose a `.env` file. Suga shows you what it found so you can drop anything you do not want before confirming.
Saved values are hidden by default. Click the eye button beside a value to reveal it.
## Secrets
Click the lock button beside a value to mark it **Sensitive**. The value is encrypted, and once saved it is never shown again in the canvas, in logs, or through the API. You can replace it, but you cannot read it back.
You can turn this off while you are still editing. Once you save, the choice is fixed.
To make a saved sensitive value readable again, delete the variable and add it
back. There is no way to unlock it in place.
When you import a `.env` file, keys that look like secrets are marked sensitive for you. Check the review list before confirming, because saving locks them.
## Referencing Another Service
A service often needs a value that belongs to another service, like a database password or the address of an internal API. Rather than copying the value, reference it.
Type `{{` in a value field. A picker opens listing everything you can reference, and typing filters it. Pick a value and the reference drops in where your cursor was.
A reference looks like this:
```bash theme={null}
DATABASE_PASSWORD={{postgres.POSTGRES_PASSWORD}}
```
The first part is the service you are pointing at. The second is the variable on that service.
References work inside a longer value, so you can build a connection string from several of them:
```bash theme={null}
DATABASE_URL=postgres://appuser:{{postgres.POSTGRES_PASSWORD}}@{{postgres.SUGA_PRIVATE_HOSTNAME}}:5432/app
```
References are resolved when the environment is deployed, so the value your service receives is always the current one. If you change the password on the database, every service referencing it picks up the new value on the next deploy.
Two problems are caught before you can deploy. A reference to a service or variable that no longer exists is marked as broken, and references that form a loop, where two services each wait on the other, are rejected.
Renaming a variable updates the references pointing at it, so nothing breaks. Deleting one that other services reference asks you to confirm and names them.
## Values Suga Provides
Every service receives a set of variables describing where it can be reached. You will mostly use them through references, so one service can read the address of another.
| Variable | What it holds |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `SUGA_PRIVATE_HOSTNAME` | The name other services in this environment use to reach this one |
| `SUGA_PUBLIC_HOSTNAME` | The address this service serves on publicly. A custom domain once one is working, otherwise the address Suga generated |
| `SUGA_PUBLIC_TARGET_PORT` | The port inside the container that public traffic is sent to |
| `SUGA_TCP_HOSTNAME` | The host raw TCP connections are made to |
| `SUGA_TCP_PORT` | The port raw TCP connections are made to |
| `SUGA_TCP_TARGET_PORT` | The port inside the container that TCP traffic is sent to |
A variable only exists when it applies. A service with no public endpoint has no `SUGA_PUBLIC_HOSTNAME`, rather than an empty one. `SUGA_TCP_PORT` is assigned while the deploy runs, so it is not available on a service that has never been deployed.
To give one service the public address of another, reference it:
```bash theme={null}
API_URL=https://{{api.SUGA_PUBLIC_HOSTNAME}}
```
If you add a custom domain later, the reference picks it up. A copied URL would not.
A reference to a `SUGA_` value the target does not have, such as the public
hostname of a service with no public endpoint, is not reported as broken. It
resolves to nothing and your service receives the text `{{...}}` unchanged.
Check that the service you are pointing at has the endpoint you expect.
`SUGA_` is reserved. You cannot create a variable whose name starts with it.
## Build Time and Run Time
The variables above are available while your service runs. A build needs its own, because the build happens before the service exists.
Some frameworks read configuration when they build rather than when they start. Values that end up in code the browser downloads are in this group, like `VITE_` variables in a Vite app or `NEXT_PUBLIC_` variables in Next.js. Setting these as service variables has no effect, because the build already finished without them.
To set them, open the **Config** tab, click the pencil on the connected repository to open **Edit Build Configuration**, and expand **Additional Settings**.
* On an auto-detected build the field is **Environment Variables**. Values are available to the build and are not stored in the image.
* On a Dockerfile build the field is **Build Arguments**. Declare each one with `ARG KEY` in your Dockerfile, or the build will not see it. Values passed this way can be read back out of the finished image.
Whatever your build writes into its output stays there. A value used to build
browser code is readable by anyone who loads the page, whichever field you used
to supply it. Keep secrets out of client-side builds.
Saving build configuration starts a new build straight away. It does not wait for **Apply**.
Some names are reserved and will be rejected, including anything starting with `DEPOT_`, `BUILDKIT_` or `GIT_`, and common system names like `PATH`, `HOME` and `NODE_OPTIONS`.
# Networking
Source: https://docs.suga.app/configure/networking
Public and private networking for your applications
Suga provides two networking modes: **Private Networking** for internal service communication, and **Public Networking** for exposing services to the internet.
## Networking Overview
| Type | Purpose | Configuration | Security |
| ---------------- | -------------------------------- | ------------- | ----------------- |
| **Private** | Service-to-service communication | Automatic | Internal only |
| **Public HTTPS** | Web traffic with TLS | Port 443 | Automatic TLS |
| **Public TCP** | Non-HTTP protocols | Custom port | No TLS by default |
## Private Networking (Service Discovery)
All services in the same environment can communicate privately using automatic service discovery. Private traffic stays inside the environment and is never exposed to the internet.
### How It Works
**Automatic DNS:**
* Every service gets an internal hostname
* Internal DNS resolves service hostnames to addresses within the environment
* No manual configuration required
**Format:**
```
hostname:port
```
**Examples:**
* PostgreSQL: `postgres:5432`
* Redis: `redis:6379`
* API service: `api:3000`
* WebSocket server: `websocket:8080`
### Configuring Hostname and Ports
Each service has a **Private Networking** section in its **Config** tab where you can set:
* **Hostname**: the name other services use to reach this service. It starts as a DNS-safe version of the service's display name (lower case, with spaces and underscores turned into hyphens and other characters dropped), with a `-2` or `-3` suffix if that name is already taken. Override it to use a friendlier name like `postgres` or `api`. Hostnames must be unique within an environment.
* **Ports**: the ports this service listens on internally. Add every port you want reachable from other services in the same environment.
Public networking ports (HTTPS endpoints, TCP proxies, custom domains) are automatically reachable on the private hostname as well, so you don't need to list them twice.
### Connection Strings
Use service names in connection strings:
```javascript Node.js theme={null}
// PostgreSQL
const connectionString = `postgresql://user:pass@postgres:5432/database`;
// Redis
const redisUrl = `redis://:password@redis:6379`;
// HTTP API
const apiUrl = `http://api:3000/endpoint`;
```
```python Python theme={null}
# PostgreSQL
DATABASE_URL = "postgresql://user:pass@postgres:5432/database"
# Redis
REDIS_URL = "redis://:password@redis:6379"
# HTTP API
API_URL = "http://api:3000/endpoint"
```
```go Go theme={null}
// PostgreSQL
connStr := "postgresql://user:pass@postgres:5432/database"
// Redis
redisAddr := "redis:6379"
// HTTP API
apiURL := "http://api:3000/endpoint"
```
Private networking currently only works within the same environment. Services in "production" cannot reach services in "staging".
## Public Networking
Public networking exposes services to the internet. Suga offers two modes: **HTTPS** and **TCP Proxy**.
### HTTPS Endpoints
HTTPS endpoints provide secure web access with automatic TLS certificates. All HTTPS traffic goes through Cloudflare's global CDN. See [CDN and Regions](/reference/cdn-and-regions) for the edge architecture and where requests get routed.
**Features:**
* Port 443 (HTTPS)
* Automatic TLS certificates via Cloudflare
* Cloudflare CDN, WAF, and DDoS protection
* Auto-generated domain names
* Traffic spread across replicas
**Auto-Generated Domains:**
Suga generates a domain for each HTTPS endpoint. It combines the service's ID, the environment name, and a label identifying the cluster your organization runs in.
Example:
```
https://k3f9x2mq7p1a-production-a1b2c3d4.us-central1.suga.run
```
The service ID is the short identifier Suga assigns, not the name you gave the service, so renaming a service does not change its generated address. The domain is fixed once the endpoint is created. You can change which port it serves, but not the address itself.
Because the address is assigned rather than chosen, avoid copying it into another service by hand. Reference it instead, so it stays correct if you add a custom domain later:
```bash theme={null}
API_URL=https://{{api.SUGA_PUBLIC_HOSTNAME}}
```
See [Environment Variables](/configure/environment-variables) for how references work, and [Custom Domains](/configure/custom-domains) to serve on your own domain instead.
**Configuration:**
Click on the service you want to expose.
In the properties panel, open the **Config** tab.
In the **Public Networking** section, click **Add** next to **Generated URL**. Specify the target port your application listens on (e.g., 3000, 8080). Public HTTPS traffic on port 443 routes to this port.
Click **Apply**. Your service will be accessible at the generated URL.
### TCP Proxy
TCP proxy exposes non-HTTP protocols to the internet.
**Use Cases:**
* Direct database access (PostgreSQL, MySQL)
* SSH connections
* Custom protocols (MQTT)
* Game servers
Standard `wss://` WebSockets go through the HTTPS path — see [WebSocket Support](#websocket-support). TCP Proxy is only needed for non-HTTP protocols.
**Features:**
* Any TCP port
* Allocated load balancer port
* No automatic TLS (use application-level encryption)
**Configuration:**
Click on the service to expose.
In the properties panel, open the **Config** tab.
In the **Public Networking** section, click **+ TCP Proxy**. Enter the port your application listens on (e.g., 5432 for PostgreSQL).
Click **Apply**. Note the allocated hostname and port in the **Public Networking** section.
Use the hostname and allocated port shown in the UI:
```
psql -h proxy.us-central1.suga.run -p 46345 -U user
```
TCP proxy does not provide TLS encryption by default. Use application-level encryption (like PostgreSQL's SSL mode) or consider keeping the service private.
## Connection Timeouts
Suga Cloud applies explicit, predictable timeouts to all public traffic so connection behaviour is consistent across deployments. These limits apply to traffic through public ingress (HTTPS endpoints and TCP Proxy) — private service-to-service connections inside an environment aren't subject to these idle timeouts.
| Timeout | Applies To | Value | What It Means |
| ---------------------- | -------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Request header timeout | HTTPS endpoints (Free plan only) | 120 seconds | Clients must finish sending HTTP request headers within 120 seconds of connecting. Protects shared edge infrastructure from slow or stalled clients. |
| Stream idle timeout | HTTPS endpoints | 5 minutes | An HTTP request, WebSocket, SSE stream, or long-polling response with no traffic in either direction for 5 minutes is closed. |
| TCP idle timeout | HTTPS endpoints, TCP Proxy | 15 minutes | A TCP connection with no application data sent in either direction for 15 minutes is closed. |
| Dead-peer detection | HTTPS endpoints, TCP Proxy | \~2.5 minutes | Suga Cloud probes idle connections and closes any whose peer has gone away (network partition, crashed client, etc.) within roughly 2.5 minutes. |
The stream idle, TCP idle, and dead-peer detection limits apply equally on every plan. The request header timeout applies to Free plan services only. See [Plan Limits](/reference/limits#free-tier-request-headers).
### Keeping Long-Lived Connections Alive
For long-lived connections — WebSockets, Server-Sent Events, persistent database connections via TCP Proxy — make sure the client or server emits traffic more often than the relevant idle timeout:
* **WebSockets:** send a ping frame every 1–2 minutes (well under the 5 minute stream idle timeout). Most WebSocket libraries can do this automatically.
* **Server-Sent Events:** emit a comment line (`: keepalive\n\n`) or heartbeat event every 1–2 minutes.
* **TCP Proxy (e.g. databases):** enable the keepalive your client supports, such as PostgreSQL `keepalives_idle`, or TCP-level `SO_KEEPALIVE` on the socket for clients without a protocol-level option. Otherwise expect to reconnect every 15 minutes.
Dead-peer detection and the TCP idle timeout are independent. Dead-peer detection only closes connections whose *peer* is gone — it does not reset the idle timer for healthy-but-quiet connections.
## Load Balancing
For services with multiple replicas, Suga spreads traffic across replicas automatically. This applies to HTTPS endpoints, TCP proxies, and private service-to-service traffic. The distribution strategy is not configurable, and Suga does not guarantee a particular one, so don't rely on requests landing on a specific replica.
Load balancing is automatic. You don't need to configure it manually.
## WebSocket Support
WebSockets work automatically with HTTPS endpoints:
**Setup:**
1. Configure your application to listen for WebSocket connections
2. Enable HTTPS on the service
3. Deploy
4. Connect using `wss://` (secure WebSocket)
Idle WebSockets are closed after 5 minutes. Have your client or server send a ping frame every 1–2 minutes to keep the connection open — see [Connection Timeouts](#connection-timeouts).
**Example:**
```javascript theme={null}
// Client
const ws = new WebSocket('wss://k3f9x2mq7p1a-production-a1b2c3d4.us-central1.suga.run');
// Server (Node.js with ws library)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });
wss.on('connection', (ws) => {
console.log('Client connected');
ws.send('Welcome!');
});
```
## Server-Sent Events Support
Server-Sent Events (SSE) work automatically with HTTPS endpoints — no special configuration required.
**Setup:**
1. Configure your application to respond with `Content-Type: text/event-stream`
2. Enable HTTPS on the service
3. Deploy
4. Connect using `EventSource` from the client
Idle SSE streams are closed after 5 minutes. Emit a comment line (`: keepalive\n\n`) or heartbeat event every 1–2 minutes to keep the connection open. See [Connection Timeouts](#connection-timeouts).
**Example:**
```javascript theme={null}
// Server (Node.js / Express)
app.get('/events', (req, res) => {
res.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});
const heartbeat = setInterval(() => res.write(': keepalive\n\n'), 90_000);
req.on('close', () => clearInterval(heartbeat));
});
// Client
const events = new EventSource('https://k3f9x2mq7p1a-production-a1b2c3d4.us-central1.suga.run/events');
events.onmessage = (e) => console.log(e.data);
```
## Network Isolation
Every environment runs inside its own isolated network boundary on Suga Cloud. Services in one environment cannot reach services in another over private networking, and the platform applies a default-deny security posture with explicit allow rules.
### Environment Boundaries
**Between Environments:**
* Services in different environments (production, staging, dev) cannot communicate privately, even within the same project
* Each environment has its own isolated network with its own private DNS
* For cross-environment communication, use public networking
**Between Projects:**
* Services in different projects cannot communicate privately
* Use public networking (HTTPS/TCP) for cross-project communication
Suga Cloud does not provision a dedicated VPC per project, and there is no cross-environment private routing. Environment isolation is enforced by network policy, not by separate networks.
### Default-Deny Posture
Every environment starts with a default-deny policy and only the traffic listed below is permitted. Anything not explicitly allowed is dropped.
**Ingress (incoming connections to your services):**
| Source | Allowed |
| ------------------------------------------------------------------- | ------------------------------------- |
| Other services in the same environment | Yes |
| Suga Cloud management traffic (TLS, ingress routing, health checks) | Yes |
| Services in other environments or projects | No |
| The public internet (direct) | No. Must go through a public endpoint |
**Egress (outbound connections from your services):**
| Destination | Allowed |
| ----------------------------------------------------------------------------------------------------- | ------- |
| DNS resolution | Yes |
| Other services in the same environment | Yes |
| Public internet (any external API or service) | Yes |
| Private IP ranges outside the environment (RFC 1918: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`) | No |
| Cloud provider metadata endpoints | No |
Blocking RFC 1918 ranges prevents services from reaching internal infrastructure they shouldn't see, including other tenants' private IPs. Blocking metadata endpoints prevents workloads from harvesting cloud credentials or instance identity from the underlying host.
### Public vs Private
* **Private networking** is internal-only and never exposed to the internet. It's the only way services in the same environment talk to each other privately.
* **Public networking** (HTTPS endpoints, TCP proxies, custom domains) requires explicit configuration on each service and routes through Suga's managed ingress with automatic TLS for HTTPS.
## Common Patterns
### Web Application
Frontend talks to backend, backend talks to database:
```mermaid theme={null}
graph LR
frontend[Frontend
Public] <-->|HTTPS| api[API
Public]
api <-->|Private| postgres[Postgres
Private]
```
**Configuration:**
* `frontend`: HTTPS enabled (public)
* `api`: HTTPS enabled (public)
* `postgres`: No public networking (private only)
* `api` connects to `postgres` via `postgres:5432`
### Microservices
Multiple services communicate privately, one acts as public gateway:
```mermaid theme={null}
graph TD
client[Client
Public] <-->|HTTPS| gateway[Gateway
Public]
gateway <-->|Private| orders[Orders
Private]
gateway <-->|Private| users[Users
Private]
gateway <-->|Private| products[Products
Private]
```
**Configuration:**
* `gateway`: HTTPS enabled (public)
* `users`, `orders`, `products`: No public networking (private only)
* Gateway connects to services via private networking
## Common Questions
No, HTTPS always uses port 443. You specify your container port (e.g., 3000), and Suga routes port 443 to your container port automatically.
No, Suga automatically provisions and renews certificates for all HTTPS endpoints. Traffic from the client to Suga's gateway is encrypted, and TLS terminates at the gateway.
Yes, using TCP proxy. However, it's not recommended for security reasons. Keep databases private and access them via your application or a bastion host.
Not via private networking. Use public networking (HTTPS/TCP) or deploy related services in the same project.
Currently, public endpoints are accessible by anyone. Implement authentication in your application. IP allowlisting is planned for a future release.
# Private Docker Registries
Source: https://docs.suga.app/configure/private-registries
Use images from private registries
This guide explains how to use Docker images from private registries on Suga.
## Supported Registries
* **Docker Hub** - Private repositories
* **GitHub Container Registry (GHCR)** - `ghcr.io`
* **Google Container Registry (GCR)** - `gcr.io` and Artifact Registry
* **Amazon ECR** - Elastic Container Registry
* **Azure Container Registry (ACR)**
* **Self-hosted** - Harbor, GitLab, Nexus, etc.
## Adding Registry Credentials
Registry credentials are stored per environment, keyed by registry hostname. Enter them once for a registry and every service in that environment pulling from the same host can use them. Environments do not share credentials, so staging and production each need their own.
Open the Add palette and choose **Service from Container**, or select an existing service and open its **Config** tab.
Enter the full image reference, including the registry host, for example `ghcr.io/username/my-app:v1.2.3`. Suga reads the registry host from this, so there is no separate registry field.
Expand **Registry credentials** and fill in:
* **Username** - Your username or access key
* **Password** - Your password or access token
Click **Apply**. Suga authenticates automatically using the stored credentials.
## Registry Configuration
| Registry | Host in the image URI | Username | Password |
| --------------- | ------------------------------------------ | --------------- | --------------------------------------- |
| **Docker Hub** | `docker.io` | Your username | Access token |
| **GHCR** | `ghcr.io` | GitHub username | Personal access token (`read:packages`) |
| **GCR** | `gcr.io` | `_json_key` | Service account JSON key |
| **ECR** | `{account}.dkr.ecr.{region}.amazonaws.com` | `AWS` | `aws ecr get-login-password` output |
| **ACR** | `{name}.azurecr.io` | Registry name | Admin password or SP password |
| **Self-hosted** | Your registry hostname | Your username | Your password |
**ECR tokens expire after 12 hours.** Suga only supports username and password credentials, so there is no way to have it fetch a fresh ECR token for you. Update the password before it expires, or push your images to a registry with long-lived tokens, such as GHCR.
## Image Name Format
Always include the full registry in the image name:
```
ghcr.io/username/my-app:latest
gcr.io/project-id/my-app:v1.0.0
123456789012.dkr.ecr.us-west-2.amazonaws.com/my-app:latest
yourregistry.azurecr.io/my-app:latest
```
Omitting the registry prefix (e.g., `username/my-app`) assumes Docker Hub.
## Image Pull Behavior
Suga always pulls the latest version of an image on each deployment. This ensures you get the most recent version even when using the same tag.
Using `:latest` in production is not recommended. Use specific version tags (e.g., `v1.2.3`) for reproducible deployments.
## Troubleshooting
**Check:**
* Registry URL format is correct
* Credentials haven't expired
* Image name and tag exist
* Token has read permissions
**Test locally:** `docker login registry-url && docker pull image:tag`
Use full image name including registry:
```
ghcr.io/username/image:tag ✓
username/image:tag ✗ (assumes Docker Hub)
```
ECR tokens expire after 12 hours. Regenerate the token with `aws ecr get-login-password` and update the password on the container. If you redeploy often, copy your images to a registry with long-lived tokens instead.
Docker Hub limits: 100 pulls/6h (anonymous), 200 pulls/6h (authenticated)
Solutions:
* Add Docker Hub credentials (increases to 200)
* Use GHCR, GCR, or other registry
* Upgrade to Docker Hub Pro
## Security Best Practices
Grant only read permissions:
* Docker Hub: Read-only access token
* GitHub: `read:packages` scope
* GCR: "Storage Object Viewer" role
* ECR: `AmazonEC2ContainerRegistryReadOnly`
* ACR: `AcrPull` role
Rotate every 90 days, after team member departure, or after suspected compromise.
Use `myapp:v1.2.3` instead of `myapp:latest` for reproducible deployments.
# Storage
Source: https://docs.suga.app/configure/volumes
Volumes, databases, and backup strategies
This reference covers persistent storage on Suga: volumes for data persistence, database templates, and backup strategies.
## Volumes
Volumes provide persistent block storage. Unlike service filesystems (ephemeral), volume data persists across restarts, redeployments, and rollbacks.
### Creating a Volume
1. Add a volume to the canvas
2. Set size (see plan limits below)
3. Drop the volume onto a service
4. Set the mount path
5. Click **Apply**
### Volume Constraints
* **Services per volume**: 1 (volumes cannot be shared between services)
* **Replicas with volumes**: 1 (required for data consistency)
* **Size limits**: vary by plan, see [Plan Limits](/reference/limits#volume-limits)
Volume storage also counts toward your organization's overall storage pool.
Services with volumes must have exactly 1 replica. Volumes cannot be shared across multiple instances or services.
### Data Persistence
**Data survives:**
* Container restarts
* Redeployments
* Service crashes
* Rollbacks (data stays current, not rolled back)
**Data is lost if:**
* Volume is deleted
* Environment is deleted
Rolling back a deployment does NOT roll back volume data. However, rolling back to a deployment before the volume existed will result in it being deleted.
***
## Database Templates
Templates provide pre-configured databases with volumes attached.
### PostgreSQL
```yaml theme={null}
Image: postgres:16-alpine
Port: 5432
Volume: /var/lib/postgresql/data
Environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: [your password]
POSTGRES_DB: postgres
```
**Connection from other services:**
```
postgresql://postgres:PASSWORD@postgres:5432/postgres
```
### Redis
```yaml theme={null}
Image: redis:7-alpine
Port: 6379
Volume: /data
Command: redis-server --appendonly yes --requirepass [password] --maxmemory 200mb --maxmemory-policy allkeys-lru
```
The template caps Redis at 200 MB of data and evicts the least recently used keys when it fills up. Raise `--maxmemory` if you give the service more memory, and change `--maxmemory-policy` to `noeviction` if you are using Redis as a durable store rather than a cache.
**Connection:**
```
redis://:PASSWORD@redis:6379
```
### MariaDB
```yaml theme={null}
Image: mariadb:11
Port: 3306
Volume: /var/lib/mysql
Environment:
MARIADB_ROOT_PASSWORD: [your password]
MARIADB_DATABASE: mydb
MARIADB_USER: [application user]
MARIADB_PASSWORD: [application user password]
```
`MARIADB_USER` and `MARIADB_PASSWORD` are both required. The image creates that user and grants it access to `MARIADB_DATABASE`.
**Connection:**
```
mysql://USER:PASSWORD@mariadb:3306/mydb
```
### Connecting to Databases
Use service names as hostnames for private networking:
```javascript theme={null}
// Node.js - PostgreSQL
const pool = new Pool({
host: 'postgres', // Service name
port: 5432,
password: process.env.DB_PASSWORD
});
// Node.js - Redis
const redis = new Redis({
host: 'redis',
port: 6379,
password: process.env.REDIS_PASSWORD
});
```
***
## Volume vs External Storage
**Use Volumes when:**
* Running your own database
* Need direct filesystem access
* Storing small uploads or state
**Use External Storage (S3, R2) when:**
* Files exceed your plan's storage limits
* Need to share files across services
* Require public CDN access
* Want automatic scaling
***
## Common Questions
No, each volume can only mount to one service. For shared data, use a database or external object storage.
You can increase a volume's size. You cannot decrease it. The underlying storage does not support shrinking, so the canvas blocks a smaller value and the change would be rejected even if it got through. To end up with a smaller volume, create a new one at the size you want and copy the data across.
You can only access volume data from within the container. Use database connections or application APIs.
# Welcome to Suga
Source: https://docs.suga.app/introduction
Infrastructure deployment that's both fast and disciplined
Suga is under active development, so expect frequent changes as we ship. [Join our Discord](https://suga.app/chat) for support and updates.
Deploying infrastructure has meant choosing between two imperfect options: slow-but-safe configuration files, or fast-but-dangerous console clicking. Traditional Infrastructure as Code gives you version control and reproducibility, but deployments take minutes and YAML becomes unmanageable. Cloud consoles let you move quickly, but changes disappear without trace and environments drift apart.
Suga rethinks infrastructure deployment from first principles. What if you could deploy in seconds while maintaining full version control? What if every change had an audit trail, environments were instantly reproducible, and you could see your entire architecture at a glance?
## What is Suga?
Suga is an infrastructure deployment platform built around a canvas interface. Every change you make is versioned and tracked: who deployed what, when, and why. Clone entire environments for testing. Roll back to any previous state instantly.
The canvas shows your architecture visually (services, databases, connections), making it clear what you're building. But underneath, Suga maintains the discipline of Infrastructure as Code: reproducible environments, deployment history, and change tracking. You get the iteration speed of a UI with the safety guarantees of versioned infrastructure.
Whether you're deploying containers or serverless functions, Suga handles the orchestration details. Automatic HTTPS and zero-downtime updates work by default. You focus on your application; Suga manages the complexity.
## How It Works
Add services to a visual canvas. Connections between components are explicit. You can see what talks to what. Your architecture becomes documentation.
Set environment variables, allocate resources, configure networking. Every change is tracked in deployment history. You'll know exactly what changed and who changed it.
Click **Apply**. Watch your infrastructure go live. Zero-downtime deployments mean your users never see an outage.
View complete deployment history. See who deployed what, when, and with what commit message. Roll back to any previous configuration: the entire state, not just code.
Need to test something? Fork your production environment into an isolated copy. Make changes, verify they work, tear it down. Environments are reproducible.
## Key Capabilities
Deployments are fast, and zero-downtime updates keep services running while they roll out.
Every change tracked with commit messages. Full deployment history shows who changed what and when.
Clone entire environments instantly. Test changes in isolation, then tear down when done.
Return to any previous deployment state. Roll back in seconds when issues arise.
Complete record of infrastructure changes. See the commit message, timestamp, and author for every deployment.
See your infrastructure as a diagram. Connections, dependencies, and data flow become clear.
## Who is Suga For?
Suga is built for teams who want to move fast without losing infrastructure discipline:
* **Development Teams** who need rapid iteration cycles while maintaining deployment history and reproducibility
* **Small Teams** building production services who want Infrastructure as Code benefits without YAML complexity
* **Anyone** frustrated with choosing between slow-but-traceable config files and fast-but-untraceable console clicking
* **Teams** managing multiple environments (dev, staging, production) who need each one to be reproducible and forkable
## Getting Started
Ready to deploy your first application?
Deploy your first app in 5 minutes
Understand the philosophy behind Suga
Learn how projects, environments, and deployments work
Get help from the community
# Deployments
Source: https://docs.suga.app/operate/deployments
Immutable snapshots of your infrastructure configuration
Deployments are immutable snapshots that capture the complete state of your infrastructure at a specific point in time. Every time you click **Apply**, Suga creates a new deployment with your current configuration.
## What is a Deployment?
Deployments are versioned snapshots providing complete audit trails. Every deployment records who made changes, when, and why, giving you the version control and reproducibility of Infrastructure as Code without configuration files.
A deployment is a snapshot that includes:
* **All Services** - Containers and functions with their complete configuration
* **All Volumes** - Persistent storage definitions and mount paths
* **Environment Variables** - All configuration and secrets (encrypted)
* **Resource Allocations** - CPU, memory, and replica counts
* **Networking Configuration** - HTTPS endpoints, TCP proxies, and ports
* **Timestamp and Author** - When deployed and by whom
Deployments are immutable - once created, they never change. This makes them perfect for auditing, rollback, and compliance.
## Deployment Lifecycle
A deployment goes through several states:
```
Running → Active
↘ Failed
```
| State | Description |
| ------------- | ------------------------------------------------------------------ |
| **Running** | Deployment is in progress, services are starting |
| **Active** | Deployment succeeded and is the current live version |
| **Completed** | Previous deployment that was replaced by a newer active deployment |
| **Failed** | Deployment encountered an error and stopped |
Only one deployment can be active per environment at a time. Starting a new deployment replaces the previous active deployment, which moves to "Completed" status.
## Deployment Process
When you click the **Apply** button:
Suga captures your current canvas configuration, creating an immutable snapshot.
The configuration is validated:
* All required fields are set
* Resource limits are within plan allowances
* Volume mount paths are valid
Resources are created or updated.
Docker images are pulled from registries to the cluster nodes.
Containers and functions start and begin initializing.
Traffic is routed to the new services. Old services are gracefully terminated.
The deployment moves to "Active" state and becomes the current live deployment.
## Deployment History
Suga maintains a complete version control history of all deployments for each environment. This deployment history provides the same guarantees as traditional IaC tools: versioned infrastructure, audit trails, and reproducibility.
**What's Tracked:**
* Deployment ID and number
* Timestamp (when deployed)
* Author (which user triggered the deployment)
* Commit message (explaining what changed and why)
* Status (Active, Completed, Failed, Running)
* Configuration snapshot (full state at deployment time)
**Retention:**
Deployment history is unlimited on every plan. Suga does not delete old deployments, so you can roll back to any successful deployment in an environment's history.
## Active Deployment
Only one deployment is active per environment at a time:
* **Active Deployment** - The currently running version of your application
* **Previous Deployments** - Historical versions available for rollback
* **Failed Deployments** - Never become active; useful for debugging
When you create a new deployment:
1. The new deployment starts in "Running" state
2. Old active deployment remains active during the transition
3. New deployment finishes starting services
4. New deployment becomes "Active"
5. Old deployment moves to "Completed" status
This ensures zero-downtime deployments.
## Zero-Downtime Deployments
Suga uses a rolling update strategy by default:
**How It Works:**
1. A new instance starts alongside the old one. At most one extra replica runs during the rollout, and no replicas are removed early.
2. Traffic shifts to the new instance once it is running.
3. The old instance is terminated.
**Benefits:**
* No downtime during deployments
* Gradual traffic migration reduces risk
* An instance that fails to start leaves the old one serving traffic
Suga does not run health checks against your service. An instance counts as running as soon as its process starts, so a service that starts but is not yet able to serve requests can begin receiving traffic. Build in your own startup ordering if your service needs time before it is ready.
### Volumes Use a Recreate Strategy
Services with mounted volumes can only run one instance at a time, since storage is attached to a single instance. For these services, Suga switches to a **recreate** strategy:
1. The old instance stops and the volume detaches.
2. The volume attaches to the new instance.
3. The new instance starts.
There's a brief gap (usually a few seconds) while the volume hands over. Stateless containers and functions still use the rolling strategy.
Keep databases and other stateful services separate from your application tier. Then only the stateful service takes the short restart, and the rest of your stack rolls forward with zero downtime.
## Automatic Redeploys
Suga can roll out new image versions on its own, without you clicking **Apply**.
**For images Suga builds:** A push to the watched branch triggers a build. When it succeeds, the service pulls the new image and rolls out using the strategy above.
**For pre-built images from external registries:** Suga checks the registry every few minutes for a new image at the same tag. When it changes, the service rolls out.
An automatic redeploy swaps the running image in place. It does **not** create a deployment, so it does not appear in deployment history and you cannot roll it back. The last entry in history stays the deployment you applied from the canvas, and rolling back to it restores the image that deployment recorded.
Automatic redeploys reuse the active deployment's configuration and only swap the image. To change env vars, resources, or networking, apply from the canvas.
## Rolling Back Deployments
If a deployment causes issues, roll back to a previous version:
Click the **History** button in your environment.
Click on a previous deployment that was successful.
The previous configuration appears on the canvas. Review it to confirm it's the version you want.
Click **"Apply as Draft"** to load the previous configuration as a draft on your canvas.
Click **Apply** to create a new deployment with the previous configuration. This creates a new entry in deployment history, just like any other deployment.
Rolling back works like a revert commit in Git - it creates a new deployment with the old configuration rather than undoing the current deployment.
Rolling back restores configuration (images, env vars, resources, networking) but does NOT restore volume data or database state. Handle data migrations carefully.
## What Gets Rolled Back
When you roll back to a previous deployment:
**Restored:**
* Container images and tags
* Environment variables
* CPU and memory allocations
* Replica counts
* Networking configuration (HTTPS, TCP proxy, ports)
* Function code
**NOT Restored:**
* Volume data (files persisted to disk)
* Database records (data in PostgreSQL, MariaDB, etc.)
* External service state (uploaded files to S3, third-party API data)
Always test database schema changes in staging before production. If a migration causes issues, you may need to manually revert the database in addition to rolling back the deployment.
## Viewing Deployment Details
Click on any deployment in the history to view:
**Deployment Metadata:**
* Deployment number and ID
* Timestamp
* Triggered by (user)
* Status
* Duration
**Configuration Snapshot:**
* All services with full configuration
* All volumes with sizes and mount paths
* Complete environment variables (values are masked for security)
* Resource allocations
* Networking setup
**Deployment Logs:**
* Real-time logs during deployment
* Stage-by-stage progress
* Errors or warnings
## Deployment Triggers
Deployments can be triggered in several ways:
**Manual Deployment (Current):**
* Click the **Apply** button in the canvas
* Immediate deployment of current configuration
**API Deployment (Coming Soon):**
Public API for triggering deployments from CI/CD pipelines is coming soon in a future release.
**Preview Environments (Coming Soon):**
Automatic deployments for pull requests (Preview Environments) are coming soon in a future release.
## Common Questions
No, only one deployment can be active per environment at a time. Starting a new deployment replaces the previous active one.
No, you must deploy to each environment separately. Deploy to staging first, test, then deploy to production.
The deployment moves to "Failed" state and the previous active deployment continues running. Your application is not affected by failed deployments.
Not currently. Deployments are triggered manually by clicking the **Apply** button. Scheduled and automated deployments are planned for future releases.
Deployments are atomic per service. If a service fails to deploy, it doesn't affect other services. The entire deployment may complete with some services failing.
## Deployment vs. Release
**Deployment:**
* Technical operation of provisioning infrastructure
* Happens in Suga when you click **Apply**
* Immediate, automated process
**Release:**
* Business decision to make new features available
* May involve multiple deployments (staging, then production)
* Can include marketing, documentation, announcements
In Suga, you deploy frequently (even multiple times per day). You release features when ready.
# Logs
Source: https://docs.suga.app/operate/logs
Structured logging, severity detection, retention, and limitations
How logs are captured, how severity is detected, which logging libraries work out of the box, how long logs are kept, and the known limitations.
For metrics and the wider observability overview, see [Observability](/operate/metrics).
## How logging works
No SDK or extra library is required:
* Anything your container writes to **stdout** or **stderr** is captured.
* Each line is parsed, assigned a severity, and appears in the logs explorer within seconds.
* One line in your container is one entry in the explorer. Multi-line output is split into separate entries (see [Limitations](#limitations-and-gotchas)).
Find your logs in the **Logs** tab of the service properties panel. Select a service on the canvas to open it.
Select **Open in Logs explorer** for the full view: a histogram of volume by level over time, level facets for filtering, a per-replica toggle, a time-range picker, and a detail panel for individual entries.
## Structured logging
Plain text gives you logs, but structured logging gets them correctly leveled.
Each line is parsed as JSON. When parsing succeeds, Suga reads the severity out of it (see below). The rest of the line is stored and shown as the message.
Individual JSON keys are not broken out into separate searchable fields. Search is case-insensitive and matches anywhere in the message, so searching for `user_id` finds every line containing that text. Filtering by level, service, and replica is done with the facets, not the search box.
### How severity is detected
Severity is read from the parsed JSON in priority order. The first matching field wins:
| Priority | Field | Type | Common producers |
| -------- | ----------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `severity_number` | OTLP integer, 1 to 24 | OpenTelemetry Logs SDK |
| 2 | `levelname` | string | Python `python-json-logger` |
| 3 | `level` | numeric or string | pino, bunyan, roarr (numeric 10/20/30/40/50/60); winston, zap, zerolog, slog, logrus, structlog, logback, log4j, Microsoft.Extensions.Logging, Serilog (string `"info"`, `"ERROR"`, etc.) |
| 4 | `severity` | string | GCP Cloud Logging convention |
**Emit only one severity field per line.** If more than one is present, the
result is undefined. Pick one logger and let it own the field.
### Worked examples
Each emits a JSON line that gets parsed and leveled correctly.
```ts Node (pino) theme={null}
import pino from "pino";
const logger = pino();
logger.warn({ userId }, "user not found");
// emits: {"level":40, ..., "msg":"user not found"}
// detected as WARN via priority 3 (numeric level)
```
```python Python (python-json-logger) theme={null}
import logging
from pythonjsonlogger.json import JsonFormatter
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
log = logging.getLogger(__name__)
log.addHandler(handler)
log.setLevel(logging.INFO)
log.warning("user not found", extra={"user_id": user_id})
# emits: {"levelname": "WARNING", ..., "message": "user not found"}
# detected as WARN via priority 2 (levelname)
```
```go Go (slog) theme={null}
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Warn("user not found", "user_id", userID)
// emits: {"time":"...","level":"WARN", ..., "msg":"user not found"}
// detected as WARN via priority 3 (string level)
```
## Library compatibility
If you use one of these libraries with JSON output enabled, severity is detected out of the box:
| Library | Language | Field set |
| ---------------------------- | -------- | --------------------------- |
| OpenTelemetry Logs SDK | any | `severity_number` (1 to 24) |
| python-json-logger | Python | `levelname` |
| pino | Node.js | `level` (10/20/30/40/50/60) |
| bunyan | Node.js | `level` (10/20/30/40/50/60) |
| roarr | Node.js | `level` (10/20/30/40/50/60) |
| winston | Node.js | `level` (string) |
| zap | Go | `level` (string) |
| zerolog | Go | `level` (string) |
| slog | Go | `level` (string) |
| logrus | Go | `level` (string) |
| structlog | Python | `level` (string) |
| logback | Java | `level` (string) |
| log4j | Java | `level` (string) |
| Microsoft.Extensions.Logging | .NET | `level` (string) |
| Serilog | .NET | `level` (string) |
| GCP Cloud Logging | any | `severity` (string) |
For any library not listed, emit JSON with a top-level `level` (string or numeric) or `severity_number` (1 to 24) and it will be detected.
## Retention
How long logs stay in the explorer depends on your plan:
| Plan | Retention |
| ---- | --------- |
| Free | 1 day |
| Pro | 7 days |
Logs older than your retention window are removed from the explorer entirely. There is no archive to recover them from.
## Limitations and gotchas
**`console.warn` and `console.error` are not auto-detected.**
Plain text only becomes WARN or ERROR when the body contains a word-bounded match for one of: `warn`, `warning`, `error`, `err`, `fatal`, `panic`, `exception`, `critical`, `crit`, `debug`. So `console.warn("user not found")` shows up as **info**. The word boundaries keep phrases like "no errors" from being misclassified. Use a structured logger for reliable levels.
**A Datadog-style `status` field is ignored.**
Many apps log `{"status": 500}` for an HTTP status or `{"status": "error"}` for business state, so `status` is left alone. Use `level`, `severity`, `levelname`, or `severity_number` instead.
**Multi-line output is split into one entry per line.**
A bare `console.error(err)` in Node prints `Error: ...` followed by each stack frame on its own line, and every line becomes a separate entry. Log the error through a structured logger so the stack stays inside one JSON line as a field (for example `logger.error({ err }, "request failed")` with pino).
**Emit one severity field per line.**
When more than one is present, the result is undefined.
# Observability
Source: https://docs.suga.app/operate/metrics
Logs, metrics, and debugging
This reference covers observability on Suga: viewing logs, monitoring metrics, and debugging issues.
## Logs
Logs have their own reference page. See [Logs](/operate/logs) for structured logging, severity detection, library compatibility, retention, and limitations.
***
## Metrics
Select a service on the canvas and open the **Status** tab in the properties panel. CPU and memory charts appear below the deployment status, broken down per replica.
### CPU Usage
Shows CPU cores consumed over time.
| Pattern | Interpretation |
| ------------------- | -------------------------------------- |
| Consistently > 80% | Increase CPU allocation |
| Consistently \< 20% | Consider decreasing (save costs) |
| At 100% | Throttled, users experiencing slowness |
### Memory Usage
Shows MiB/GiB consumed over time.
| Pattern | Interpretation |
| ------------------- | ------------------------------------------------- |
| Consistently > 80% | Risk of the service being killed, increase memory |
| Growing steadily | Possible memory leak |
| Consistently \< 30% | Over provisioned |
Memory at 90%+ means the service is at high risk of being killed and restarted. Increase the memory allocation.
# Quickstart Guide
Source: https://docs.suga.app/quickstart
Deploy your first application with full version control and audit trails
Deploy your first application with full version control and audit trails. Every change you make will be tracked, versioned, and instantly rollback-able.
## Create Your Account
Head to [dashboard.suga.app/signup](https://dashboard.suga.app/signup) and complete the signup process. You'll create an organization and pick the region it runs in. Every environment in the organization runs in that region, so choose the one closest to your users.
## Create a Project
Click **New project** in the dashboard, then **Create empty project**. Your project is created and the canvas opens automatically.
This guide starts from an empty canvas so you can add a function by hand. You can also [import a GitHub repository](/concepts/projects#import-from-a-github-repository) or start from a template.
## Add a Function
Click **Add** in the top right of the canvas (or right-click empty space) to open the Add palette, then select **Function**. A new Deno function appears on the canvas with a default Hello World handler.
## Configure Public Access
Click on the function you just added to open the properties panel.
Go to the **Config** tab and find the **Public Networking** section. The **Generated URL** row is always there. Click **Add** next to it and set the target port.
Functions default to port 8080, which is already in the **Private Networking** → **Ports** list. The generated URL routes public traffic on port 443 to that port.
Suga provisions a TLS certificate, configures DNS, and routes public HTTPS traffic to your function. You get a URL like `https://k3f9x2mq7p1a-production-a1b2c3d4.us-central1.suga.run`.
## Deploy
Click **Apply** in the top right. Enter a commit message explaining what you're deploying (e.g., "Initial deployment of Hello World function"). This message becomes part of your deployment history, creating an audit trail of all infrastructure changes.
## Test Your Function
Once deployed, open the HTTPS URL from the public networking configuration. You should see a JSON response: `{ "message": "Hello from Deno function!" }`.
Your first function is live on the internet with HTTPS!
## What We Just Did
In addition to deploying a function, you've created a versioned, auditable infrastructure deployment:
1. **Deployment History** - Your deployment is recorded with a commit message, timestamp, and author. View it in the **Status** tab.
2. **Instant Rollback** - You can roll back to this exact state anytime, restoring the complete infrastructure configuration.
3. **Environment Cloning** - You can create a new environment that clones this one, giving you an isolated copy for testing changes.
4. **Complete Audit Trail** - Every future change will be tracked with who, when, and why.
Suga automatically handled:
* TLS certificate provisioning via Cloudflare
* DNS configuration and Cloudflare CDN setup
* WAF and DDoS protection
* Load balancing
* Zero-downtime deployment orchestration
All infrastructure changes are now version controlled, just like code. No configuration files, no multi-minute deployments, no lost history.
## Next Steps
Learn about containers and functions
Add databases and persistent storage
Monitor your application with logs and metrics
Learn about projects, environments, and deployments
## Need Help?
* Join our [Discord community](https://suga.app/chat) for support
* Email us at [support@suga.app](mailto:support@suga.app)
* Browse the [full documentation](/concepts/overview)
# Billing and Resource Allocation
Source: https://docs.suga.app/reference/billing
How Suga bills for CPU, memory, storage, and network: you pay for what you allocate, metered per second, and services can burst above their allocation for free
Suga bills for the resources you allocate to each service. This page explains what that means, how bursting works, and how to size your services so you only pay for what you need.
For the rates themselves, see [suga.app/pricing](https://www.suga.app/pricing). For per-tier caps and resource pools, see [Plan Limits](/reference/limits).
## You pay for what you allocate
When you set CPU and memory on a service, you are making a reservation: that capacity is set aside for your service, guaranteed, for as long as it runs. Your bill is for the reservation, metered per second:
* **CPU:** billed per core-second of allocated CPU.
* **Memory:** billed per GiB-second of allocated memory.
* **Storage:** billed per GiB-second of volume size.
* **Network egress:** the exception, is billed per MiB actually transferred out, since traffic can't be reserved in advance.
A service that is stopped, or an environment that is paused, is not billed for CPU or memory. Volumes bill for as long as they exist.
What your service *actually consumes* doesn't appear anywhere in that list. A service allocated 1 CPU that idles at 2% costs the same as one that runs flat out, which is why allocation size is the number to get right.
## Allocation is a floor, not a ceiling
On some platforms the resource numbers you set are *maximums* and you're billed for measured usage. That means the numbers act like a cap. On Suga your allocation is a *minimum*, it's a guaranteed to be available for your workload, but your service can use **more** when it needs to and that extra is free.
When usage rises above your allocation, the service can burst into spare capacity on the underlying host. Burst usage is free, billing never rises above your allocation, no matter how far or how often you burst.
Bursting is opportunistic, not guaranteed, it uses capacity that happens to be spare, so treat it as headroom for spikes rather than capacity you plan around:
* **CPU** above your allocation is throttled when the machine is busy. The service keeps running at its guaranteed floor, it just doesn't get the bonus.
* **Memory** above your allocation can be reclaimed when the machine is under pressure, which risks terminating the process using it. Never rely on burst memory for steady-state or startup needs, if your service needs it to boot or to sit idle, that memory belongs in the allocation.
* **Storage** never bursts, a volume is exactly its configured size.
## Sizing a service
The practical rule is to **allocate for steady state, burst for spikes.**
1. Deploy with a modest allocation.
2. Watch the service's real usage at normal load in [Metrics](/operate/metrics).
3. Set CPU to roughly its steady-state draw, brief peaks (request spikes, cron jobs, startup) can burst for free.
4. Set memory to what it needs at rest plus what it needs to start, with margin. Memory is a resource where under-allocating can cause issues.
If you came from a usage-billed platform, you may be used to setting generous numbers "just in case", since there, the cap costs nothing unless used. Here most services run comfortably on a smaller allocation than a usage-billed platform might suggest, because the spikes are included.
## Credits and overage
Paid plans include hosting credits each billing cycle (e.g. \$20 per seat per month), applied automatically against usage charges. When usage exceeds your included credits, the difference appears on your invoice as overage at the standard rates.
The [billing page](https://app.suga.app/org/billing) shows your current cycle's usage, remaining credits, and projected invoice.
# Bring Your Own Cluster (BYOC)
Source: https://docs.suga.app/reference/byoc-kubernetes
Run Suga on your own Kubernetes infrastructure
BYOC allows you to run Suga on your own Kubernetes infrastructure while using the Suga dashboard for management. You get full control over where applications run while maintaining Suga's simplicity.
BYOC is part of an Enterprise agreement and is set up with our team. It is not something you enable yourself from the dashboard. This page describes how it works and what your cluster needs. To talk through it for your environment, [contact us](/support/contact).
## BYOC vs Suga Cloud
| Aspect | Suga Cloud | BYOC |
| ----------------- | --------------------- | ------------------------------------ |
| **Setup** | Zero infrastructure | You manage K8s cluster |
| **Control** | Suga manages | Full control |
| **Data Location** | Suga's infrastructure | Your infrastructure |
| **Regions** | US, Europe, Australia | Any region/cloud/on-prem |
| **Best For** | Most users | Enterprise, compliance, existing K8s |
## Prerequisites
* **Kubernetes 1.24+** with cluster-admin access
* **LoadBalancer support** - Cloud provider integration or MetalLB for bare metal
* **Default storage class** - Must support `ReadWriteOnce` access mode for volumes
* **Outbound internet access** - To pull container images and connect to Suga API
Suga automatically installs **Envoy Gateway** (Gateway API) and manages **TLS certificates** and **DNS records** during cluster initialization. You don't need to set these up.
### Supported Platforms
GKE, EKS, AKS, self-managed, on-premises, DigitalOcean, Linode, Civo, and other K8s providers.
## Architecture
```mermaid theme={null}
graph LR
dashboard[Suga Dashboard] --> backend[Suga Backend]
backend -->|Kubernetes API| apiserver[K8s API Server
Your Cluster]
apiserver --> apps[Your Applications]
```
* **Direct API Connection** - Suga connects directly to your Kubernetes API server (no agent installed)
* **Encrypted Credentials** - Your cluster credentials are stored encrypted in Suga's database
* **Standard K8s API** - All operations use the Kubernetes REST API
* **Your Infrastructure** - Workloads and data run entirely in your cluster
## Setup
Go to **Cluster** in the left sidebar and connect your cluster.
Follow the guided setup to provide your cluster credentials. The UI will walk you through entering your API server URL and authentication details.
After adding, the dashboard should show "Connected" with a green indicator. Suga will automatically initialize the cluster with Envoy Gateway and required components.
Need help connecting your cluster? [Contact support](/support/contact) for assistance.
## Namespaces
Suga creates one namespace per environment, named `suga-` followed by the environment's ID:
```
suga-3f8a1c92-7b4e-4d21-9c05-6ea2f0b81d47
```
The name is not derived from the environment's display name, so an environment called "production" does not get a `suga-production` namespace. Find the ID in the environment's dashboard URL.
## Direct Cluster Access
With BYOC, you have full kubectl access. Set the namespace to the environment you want:
```bash theme={null}
export NS=suga-3f8a1c92-7b4e-4d21-9c05-6ea2f0b81d47
# List pods
kubectl get pods -n $NS
# View logs directly
kubectl logs my-api-xxxxx -n $NS
# Execute commands in pod
kubectl exec -it my-api-xxxxx -n $NS -- /bin/sh
# Port forward for debugging
kubectl port-forward svc/postgres 5432:5432 -n $NS
```
## Security Considerations
* Use a dedicated ServiceAccount with least-privilege permissions where possible
* Rotate credentials periodically
* Suga stores credentials encrypted at rest (AES-256-GCM)
* All API communication is TLS-encrypted
Implement network policies to restrict traffic between namespaces. See Kubernetes documentation for examples.
Apply Pod Security Standards to Suga namespaces:
```bash theme={null}
kubectl label namespace suga- \
pod-security.kubernetes.io/enforce=baseline
```
Suga stores secrets as Kubernetes Secrets. For enhanced security, use External Secrets Operator with your vault solution or enable Kubernetes encryption at rest.
## Cost
**Suga Platform:** Pricing for BYOC has not been set. [Contact us](/support/contact) for details.
**Your Infrastructure:** Kubernetes cluster costs depend on your cloud provider. Typical range: \$100-1500+/month depending on size.
# CDN and Regions
Source: https://docs.suga.app/reference/cdn-and-regions
How Suga Cloud distributes traffic across the global edge and Suga regions
Public HTTPS requests to Suga services enter through Cloudflare's global edge before reaching the Suga region that hosts your environment. The edge handles TLS, caching, and filtering, and the region runs your service. TCP proxy traffic takes a different path (see [Request Path](#request-path)).
## Edge Network
HTTPS traffic to a Suga service is served through Cloudflare's global network. This applies to both auto-generated Suga domains and [custom domains](/configure/custom-domains).
**At the edge, you get:**
* TLS termination with automatically provisioned and renewed certificates
* A managed WAF and DDoS protection
* Static asset caching and compression
Once the edge has handled the request, traffic is forwarded to the Suga region hosting your environment. See [HTTPS Endpoints](/configure/networking#https-endpoints) for the service-level configuration.
## Regions
Each organization picks a region when its Suga Cloud account is set up, and every [environment](/concepts/environments) in that organization runs in that region. The regions currently open to new organizations are:
| Area | Region | Location |
| ------------ | ---------------------- | --------------------- |
| Americas | `us-central1` | Iowa, USA |
| Europe | `europe-west1` | St. Ghislain, Belgium |
| Asia-Pacific | `australia-southeast1` | Sydney, Australia |
All environments in an organization share the same region. To run workloads in multiple regions today, [contact support](/support/contact). Region migration and multi-region setup are handled manually.
## Request Path
A public HTTPS request follows this path:
```mermaid theme={null}
graph LR
client[Client] -->|HTTPS| edge[Cloudflare Edge
TLS · WAF · CDN]
edge -->|Forwarded| ingress[Suga Region
Ingress]
ingress -->|Routed| service[Your Service]
```
The client connects to the closest Cloudflare location, Cloudflare forwards the request to the regional ingress for the environment, and the ingress routes the request to one of your service replicas.
TCP proxy traffic skips the edge layer and connects directly to the regional load balancer, since Cloudflare's HTTPS edge does not apply to raw TCP. See [TCP Proxy](/configure/networking#tcp-proxy).
## DNS Architecture
Suga manages DNS records on your behalf. You don't need to configure them. They're documented here so you can understand what gets created when you enable a public endpoint or attach a custom domain.
**Suga-generated HTTPS domains** resolve through Cloudflare to the regional ingress for the environment. This is what backs the auto-generated URL shown in the dashboard.
**Custom domains** use a CNAME target of the form:
```
.cname.
```
The hash is derived from your environment, so the target is different for every environment and you cannot construct it yourself. Copy the exact value Suga shows you when you add the domain, and point your domain (e.g. `app.example.com`) at it. Your domain then gets the same edge TLS, WAF, DDoS protection, and caching as a Suga-generated one. See [Custom Domains](/configure/custom-domains) for the setup steps.
**TCP proxy endpoints** use a non-proxied DNS record so raw TCP traffic can reach the regional load balancer directly. The hostname is allocated automatically when you add a TCP proxy.
## TLS and Certificates
Certificates are provisioned and renewed for you, on Suga-generated domains and on custom domains. You never touch a certificate or a private key, and there is nothing to renew or monitor.
Traffic is encrypted on every hop between the visitor and the Suga region, in both directions.
One case needs something from you. An apex domain, like `example.com` rather than `app.example.com`, needs a `_suga-verify` TXT record to prove you own it. See [Custom Domains](/configure/custom-domains#configuring-an-apex-domain).
## What Suga Manages vs What the Edge Manages
| Suga manages | The edge manages |
| ---------------------------------------- | ----------------------- |
| DNS records for Suga and custom domains | Caching and cache rules |
| TLS certificate provisioning and renewal | Compression |
| Regional routing to your environment | Image optimization |
| Onboarding your custom domain | Minification |
Whichever of these features are active depends on Cloudflare's zone configuration. Suga doesn't expose per-tenant overrides.
## Common Questions
Yes. The region is selected when your Suga Cloud account is set up and applies to every environment in the organization. To change region after the fact, [contact support](/support/contact).
Not today. All environments in an organization share the same region. If you need workloads in more than one region, [contact support](/support/contact).
No. These behaviors are controlled by Cloudflare's zone configuration, and Suga doesn't expose per-tenant overrides.
Yes. We add regions over time. [Contact support](/support/contact) if a specific region matters for your workload.
## Next Steps
HTTPS endpoints, TCP proxy, and private networking
Serve services from your own domain
# Service Configuration
Source: https://docs.suga.app/reference/configuration
Templates, environment variables, resources, scaling, and secrets
This reference covers all service configuration options: templates, environment variables, resource allocation, scaling, and secrets management.
## Templates
Templates are pre-configured services with production-ready defaults.
### What Templates Provide
* **Docker images** with tested versions
* **Environment variables** with validation and auto-generation
* **Networking and volumes** configured automatically
* **Multi-service stacks** with connections pre-wired
### Using a Template
1. Open the Add palette and choose **Template**
2. Select a template to add to your canvas
3. Fill required fields (passwords can be auto-generated)
4. Customize as needed (resources, env vars, networking)
5. Click **Apply**
All template settings can be modified after adding.
### Multi-Service Templates
Some templates deploy complete stacks (app + database + cache) with all connections configured automatically, including service-to-service networking and shared environment variables.
***
## Environment Variables
Environment variables configure your services at runtime.
### Adding Variables
1. Select service → **Env Vars** tab
2. Click **Add Variable**
3. Enter key (e.g., `DATABASE_URL`), value, and mark it **Sensitive** for secrets
4. Click **Apply**
### Common Variables
```bash theme={null}
# Database connections (use service names as hostnames)
DATABASE_URL=postgresql://user:password@postgres:5432/database
# API keys (mark as Sensitive)
STRIPE_SECRET_KEY=sk_live_...
API_KEY=your-api-key
# Application config
NODE_ENV=production
PORT=3000
```
### Accessing in Code
**Node.js:** `process.env.DATABASE_URL`
**Python:** `os.environ.get('DATABASE_URL')`
**Go:** `os.Getenv("DATABASE_URL")`
**Deno:** `Deno.env.get("DATABASE_URL")`
### Environment-Specific Values
Each environment has independent variables. Production and staging can have different database URLs, API keys, and feature flags without leaking between environments.
***
## Resources
Resources define CPU and memory allocation per service.
### CPU
CPU is set with a slider, not a fixed list of sizes. It starts at 0.05 cores and moves in steps of 0.05, up to the maximum your plan allows. See [Plan Limits](/reference/limits) for the maximum on each plan.
New services start at 0.1 cores.
**Throttling:** If your service exceeds CPU allocation, it gets throttled (slowed down) but doesn't crash.
### Memory
Memory is also a slider, in steps of 8 MiB, up to your plan maximum. New services start at 128 MiB.
**OOM Kills:** If your service exceeds memory, it will be terminated and restarted automatically.
A service killed for running out of memory loses in-memory state. Increase memory if you see this happening in logs.
### CPU and Memory Ratio
On Suga Cloud, per-service memory must fall within **1 GiB to 6.5 GiB per CPU core**. This is not a suggestion. A service whose CPU and memory fall outside the ratio is rejected, and you are told the valid memory range for the CPU you chose.
The sliders bound themselves to the valid window, so moving CPU can move memory with it. Memory is adjusted up or down to stay inside the range. Nothing is silently rounded up behind your back.
| CPU | Valid Memory Range |
| ---------- | ------------------- |
| 0.25 cores | 256 MiB – 1.625 GiB |
| 0.5 cores | 512 MiB – 3.25 GiB |
| 1 core | 1 GiB – 6.5 GiB |
| 2 cores | 2 GiB – 13 GiB |
| 4 cores | 4 GiB – 26 GiB |
### Plan Limits
Per-service maximums and organization-wide pool budgets vary by plan. See [Plan Limits](/reference/limits) for full details.
## Scaling
Scale applications by adding resources (vertical) or replicas (horizontal).
### Replicas
Replicas are identical copies of your service running simultaneously:
* **Load Balancing** - Traffic distributed automatically
* **Redundancy** - If one fails, others continue serving
* **Rolling Updates** - New versions deploy gradually
### Setting Replicas
1. Select service → **Config** tab → Replicas
2. Set the number of replicas
3. Click **Apply**
### Volume Limitation
Services with volumes can only have **1 replica**. Volumes cannot be shared across instances.
Keep databases at 1 replica and scale the stateless application services that connect to them.
### Cost
Replicas multiply resource costs:
* 1 replica with 1 CPU: 1x cost
* 3 replicas with 1 CPU: 3x cost
### Vertical Autoscaling
Enable autoscaling on a service to let Suga Cloud adjust CPU and memory between bounds you set, based on actual usage:
* **Minimum**: the baseline allocation, always reserved
* **Maximum**: the ceiling Suga will scale to under load
When possible, resources are resized in place without restarting your service. If the runtime needs to restart to pick up a new memory limit, the service is restarted with the new allocation.
For autoscaling services, the **maximum** values count toward your organization's resource pool. Suga reserves the burst ceiling rather than the baseline. See [Plan Limits](/reference/limits#organization-resource-pools).
***
## Common Questions
Yes, by reference. Each service owns its own variables, but a variable's value can point at another service's variable using `{{hostname.KEY}}`, where `hostname` is the other service's private hostname. Suga resolves the reference when you apply, so there is one place to update the value. Set a database password once on the database service and reference it from everything that connects to it.
No, resource changes require a new deployment.
No, services with volumes must have exactly 1 replica.
Service gets throttled (slowed down) but doesn't crash.
Service may be killed (OOMKilled) and restarted. Increase memory to prevent this.
# Infrastructure Discipline
Source: https://docs.suga.app/reference/infrastructure-discipline
How Suga maintains Infrastructure as Code benefits
Infrastructure as Code emerged to solve problems with manual infrastructure: no change history, inconsistent environments, no rollback capability, and no audit trails. Suga provides these same guarantees through deployment history and environment cloning, without configuration files.
## IaC Benefits Suga Provides
| Benefit | Traditional IaC | Suga |
| ------------------------ | ------------------ | ------------------------------ |
| **Version Control** | Git commits | Deployment snapshots |
| **Reproducibility** | Copy config files | Clone environments |
| **Rollback** | Git revert + apply | Activate previous deployment |
| **Review Before Deploy** | `terraform plan` | Diff shown in the Apply dialog |
| **Audit Trail** | Git history | Deployment history |
The discipline is identical: versioned, reviewable, auditable changes. The interface differs.
## Key Differences
### No Configuration Files
Traditional IaC defines infrastructure in YAML/HCL/JSON files committed to Git. Suga defines infrastructure visually on the canvas, with every change captured in deployment snapshots.
You get the same version control benefits without maintaining configuration syntax.
### Faster Deployments
| Tool | Typical Deploy Time |
| ---------------- | ------------------- |
| Terraform/Pulumi | 2-5 minutes |
| CloudFormation | 5-15 minutes |
| Suga | Seconds |
Speed doesn't compromise discipline. Deployments are still versioned, auditable, and reversible.
### Visual Architecture
Traditional IaC requires separate architecture diagrams that drift from reality. In Suga, the canvas *is* the architecture diagram, always accurate and always current.
## Compliance
Suga's deployment history satisfies standard compliance requirements:
* **Change Management** - Every deployment records author, timestamp, and description
* **Audit Trails** - Immutable history showing what changed between deployments
* **Rollback Capability** - One-click restore to any previous deployment
* **Reproducibility** - Cloning an environment creates an exact infrastructure copy
## FAQ
View pending changes in the Apply dialog before you apply them. For team workflows, deploy to staging first, verify, then deploy to production.
A public API for triggering deployments is planned for a future release.
The compliance requirement is change tracking, not configuration files. Suga's immutable deployment history provides the required audit trails: who, when, what, why.
# Plan Limits
Source: https://docs.suga.app/reference/limits
Resource limits per subscription tier: CPU, memory, replicas, storage, team, and shared resource pools
This page is the single source of truth for limits applied at each subscription tier. Limits apply at three levels: **per-organization** caps on team and project counts, **per-service** caps on a single service, and **organization-wide pools** that bound total resource usage across every service in your org.
For pricing, see [suga.app/pricing](https://www.suga.app/pricing).
## Plan Summary
| | Free | Pro | Enterprise |
| -------------- | ---- | --------------- | ---------- |
| Price | Free | \$20/seat/month | Custom |
| Members | 1 | Unlimited | Unlimited |
| Projects | 1 | 20 | Unlimited |
| Environments | 1 | Unlimited | Unlimited |
| Custom domains | 0 | 10 | Unlimited |
Member, project and environment counts are per organization. A Free organization has one seat, so it cannot invite anyone.
## Per-Service Limits
Each service can be configured up to these tier-specific maximums.
| Limit | Free | Pro | Enterprise |
| ------------ | --------- | ------- | ---------- |
| Max CPU | 0.1 cores | 4 cores | Unlimited |
| Max memory | 256 MiB | 8 GiB | Unlimited |
| Max replicas | 1 | 10 | 50 |
The floor for any service is 0.05 cores and 64 MiB. A new service starts at 0.1 cores and 128 MiB.
Replicas multiply resource usage. A service configured with 2 CPU cores and 4
replicas counts as 8 CPU cores against your organization's pool.
## Organization Resource Pools
Beyond per-service caps, every organization has a shared resource budget across **all services in all environments**. Deployments are blocked when they would exceed any pool limit.
| Pool Limit | Free | Pro | Enterprise |
| ------------------ | --------- | --------- | ---------- |
| Total CPU | 0.1 cores | 100 cores | Unlimited |
| Total memory | 256 MiB | 128 GiB | Unlimited |
| Total storage | 1 GB | 500 GB | Unlimited |
| Public TCP proxies | 0 | 5 | Unlimited |
TCP proxies are a paid feature. Free organizations cannot create one.
For services with autoscaling enabled, the **maximum** values count toward pool usage. Suga reserves the burst ceiling rather than the baseline.
You can see current usage against these pools on the Usage page in your organization sidebar.
## Volume Limits
| Volume Limit | Free | Pro | Enterprise |
| ------------------- | ---- | ----- | ---------- |
| Max size per volume | 1 GB | 10 GB | Unlimited |
Volume sizes range from 1 GB to 1000 GB and count toward your organization's storage pool. A Free organization has a 1 GB storage pool, so it can run one 1 GB volume.
## Free Tier Bandwidth
| Limit | Free | Pro and Enterprise |
| ------------------ | -------------------- | ------------------ |
| Outbound bandwidth | 5 Mbit/s per replica | Unlimited |
At 5 Mbit/s a service sends about 625 KB per second, so large responses and file downloads are noticeably slower on the Free plan than on a paid one.
## Free Tier Request Headers
| Limit | Free | Pro and Enterprise |
| ---------------------- | ----------- | ------------------ |
| Request header timeout | 120 seconds | Not applied |
Clients connecting to a Free plan service over HTTPS must finish sending their request headers within 120 seconds. This protects shared edge infrastructure from slow or stalled clients and does not limit how long a request may take once its headers have arrived. See [Connection Timeouts](/configure/networking#connection-timeouts) for the timeouts that apply on every plan.
The bandwidth limit is applied when a replica starts. Upgrading to Pro does not
lift it on services that are already running. Redeploy the service to clear it.
## Log Retention
| | Free | Pro |
| ------------- | ----- | ------ |
| Log retention | 1 day | 7 days |
## Images on the Free Plan
Free organizations can deploy Suga's approved template images, or build from a connected GitHub repository. Deploying an arbitrary image from a registry requires a paid plan. See [Templates](/concepts/services) for what is available.
## CPU and Memory Ratio
Suga Cloud requires per-service memory to fall within **1 GiB to 6.5 GiB per CPU core**. This applies to every service, on every tier.
| CPU | Valid Memory Range |
| ---------- | ------------------- |
| 0.1 cores | 102 MiB - 665 MiB |
| 0.25 cores | 256 MiB - 1.625 GiB |
| 0.5 cores | 512 MiB - 3.25 GiB |
| 1 core | 1 GiB - 6.5 GiB |
| 2 cores | 2 GiB - 13 GiB |
| 4 cores | 4 GiB - 26 GiB |
A service configured outside this ratio is rejected before it deploys. Change
CPU and memory together so the pair stays in range.
For autoscaling services, the ratio applies to both the minimum and maximum bounds.
## Vertical Autoscaling
Enable autoscaling on a service to let Suga Cloud adjust CPU and memory based on actual usage, between the limits you set.
### How It Works
You configure two values per resource:
* **Minimum**: the baseline allocation, always reserved for the service
* **Maximum**: the ceiling Suga will scale to under load
Suga Cloud monitors usage and adjusts allocation within this range, scaling up as sustained usage approaches the current allocation and scaling down when usage drops well below it.
### Resizing Behavior
When possible, Suga Cloud resizes resources in place without restarting your service. If the OS or runtime requires a restart to pick up the new memory limit, the service is restarted with the new allocation.
Services should still handle restarts: drain in-flight requests and persist
state to volumes.
### Pool Accounting
For autoscaling services, **maximum** values count toward your organization's resource pool. This reserves scale-up headroom against the pool budget. A Pro org with a 100 CPU pool and four services configured at max 25 cores has used its full pool budget, even when those services are running at their minimum.
## What Happens at a Limit
| Limit Hit | Behavior |
| ------------------------------------------ | -------------------------------------------------------------- |
| Per-service CPU or memory exceeds tier max | Deployment validation fails with a tier limit error |
| Memory:CPU ratio out of range | Deployment validation fails |
| Org pool exceeded | Deployment validation fails; existing deployments keep running |
| Replica cap exceeded | Deployment validation fails |
| Volume size or storage pool exceeded | Volume creation fails |
To increase your limits, [upgrade your plan](https://www.suga.app/pricing) or [contact us](/support/contact) about Enterprise pricing.
# Contact Support
Source: https://docs.suga.app/support/contact
Get help from the Suga team
Need help with Suga? We're here for you!
## Support Channels
### Discord Community
Join our active Discord community for:
* Real-time chat with other Suga users
* Quick answers to common questions
* Feature discussions and feedback
* Announcements and updates
Get community support
### Email Support
**Contact addresses:**
* **General Support**: [support@suga.app](mailto:support@suga.app)
* **Security Issues**: [security@suga.app](mailto:security@suga.app)
Include as much detail as possible: project name, environment, error messages, and steps to reproduce the issue.
For security vulnerabilities, please email [security@suga.app](mailto:security@suga.app) instead of posting publicly. This helps protect all users while we investigate and fix the issue.
### GitHub Issues
Use GitHub for bug reports and feature requests:
Report bugs and request features
## Before Contacting Support
Help us help you faster by including:
**For Technical Issues:**
* Project name and organization
* Environment name (production, staging, etc.)
* Service name(s) affected
* Complete error messages from logs
* Steps to reproduce the issue
* Screenshots if applicable
**For Billing Questions:**
* Organization name
* Email associated with your account
* Invoice number (if applicable)
## Community Resources
### Documentation
Start here for self-service help:
* [Quick Start](/quickstart)
* [Concepts](/concepts/overview)
* [Troubleshooting](/support/troubleshooting)
### Social Media
Follow us for updates:
* **X**: [@sugasrc](https://x.com/sugasrc)
* **GitHub**: [sugasrc/suga](https://github.com/sugasrc)
* **LinkedIn**: [Nitric (Suga parent company)](https://linkedin.com/company/nitrictech)
## Next Steps
Fix common issues
Connect with community
Learn Suga features
# FAQ
Source: https://docs.suga.app/support/faq
Common questions about Suga, the cloud deployment platform by Nitric Inc.
> Answers to the questions developers ask most often about Suga. For deeper dives, see the [Suga vs Vercel](/comparisons/suga-vs-vercel) and [Suga vs Railway](/comparisons/suga-vs-railway) comparisons, or jump into the [quickstart](/quickstart).
## Deployment Basics
### How do I deploy a Docker container?
Suga deploys Docker containers straight from a Git push, with no Kubernetes, no YAML, and no cluster to manage. It handles networking, TLS, load balancing, and scaling for you, so a container goes from repo to a live HTTPS URL in a few minutes. You get the rollback and audit trail of infrastructure-as-code without writing any.
### Do I have to write YAML or config files?
Suga deploys full-stack apps with zero config files and no Dockerfile required. You push your repo, Suga builds it automatically, and you wire your frontend, backend, and database together visually on a canvas instead of editing manifests. You can also import an existing `docker-compose.yml` to bring a multi-service project across in one step.
### Can I run long-running services rather than functions?
Suga is built for long-running services, which is where most serverless platforms fall short. Your services stay running continuously rather than cold-starting per request, and they connect to each other by name with automatic load balancing. This makes it a fit for APIs, workers, databases, and stateful backends that serverless functions handle awkwardly.
### Are deploys zero-downtime?
Suga gives you zero-downtime deploys with no infrastructure work on your end. A new version starts alongside the old one, and the old replicas are only removed once the new ones are running, so a rollout that never comes up leaves your previous version serving. You can roll back to any previous environment state (services, env vars, networking, resources) in a click, and failover and resource cleanup happen in the background.
Services with a mounted volume are the exception. A volume attaches to one replica at a time, so those services stop before the new version starts and are briefly unavailable during every deploy.
### How do I add a database?
On Suga you add a database as a service on your canvas, and it connects to your app by name automatically. Pre-configured templates exist for PostgreSQL, Redis, MariaDB, MySQL, MongoDB and more, and on a paid plan any other database that runs in a Docker container works too. Data persists across restarts, redeploys, and rollbacks, and databases are private by default unless you choose to expose them.
### Do I get HTTPS, a CDN, and DDoS protection?
Suga ships all of these by default the moment you expose a service. Public HTTPS traffic runs through Cloudflare's global edge, which provides automatic TLS, caching, a managed WAF, and DDoS absorption with no extra setup. Services stay private until you decide to make them public. TCP endpoints connect directly and do not pass through the edge.
### Where do I see logs and metrics?
Suga has observability built in, so deploy logs, runtime logs, and CPU/memory metrics are stitched together automatically. Click any service on the visual canvas and you see exactly what it's doing in real time, with no separate monitoring stack to configure.
## Comparisons
### Is Suga a fit if I'm coming from Heroku?
Suga is a strong Heroku alternative if you want the same push-to-deploy simplicity plus a visual architecture canvas, built-in observability, and security defaults that Heroku leaves to you. Like Heroku it removes infrastructure busywork, and it adds zero-downtime deploys, instant rollback, and a built-in CDN, WAF, and DDoS protection. Heroku may still suit you if you depend heavily on its specific add-on marketplace.
### How do I choose between Suga and similar platforms?
The right choice depends on what you're deploying. Vercel is best for frontend and serverless workloads, Render and Fly.io are good for container-based services (with Fly.io leaning into edge placement), Heroku is the classic simple PaaS, and Suga fits teams who want long-running services, a visual canvas, real-time observability, and security defaults in one platform without YAML or Kubernetes. If your app is mostly a static frontend, a frontend-first host is simpler, and if it's a system of connected long-running services, Suga is built for that shape. See [Suga vs Vercel](/comparisons/suga-vs-vercel) and [Suga vs Railway](/comparisons/suga-vs-railway) for deeper breakdowns.
### How does Suga compare to frontend-first platforms?
Frontend-first platforms are optimized for static sites and serverless functions. Suga is designed for long-running backend services. Your services run continuously, talk to each other over private networking, and come with built-in metrics and logs. You keep the push-to-deploy experience while running stateful, always-on workloads that serverless platforms aren't built for.
### What is the canvas?
Suga is built around a visual environment canvas, which is unusual among deploy platforms. Every service and connection appears on a single canvas, every change lands in an immutable history, and any previous state is one click away. It gives you the audit trail and rollback of infrastructure-as-code without writing any code to get it.
### Are the CDN, WAF, and DDoS protection included, or add-ons?
Suga includes a CDN, a managed WAF, and always-on DDoS protection by default, alongside network isolation, encrypted secrets, and automatic TLS. On many competing platforms these are add-ons or separate services you configure yourself. On Suga they're wired up the moment you expose a service.
### Can I bring my own Dockerfile or image?
Yes, Suga deploys both Docker containers and Dockerfiles, and it can also build your app automatically with no Dockerfile at all. You can bring an existing image, point Suga at your repo, or import a `docker-compose.yml`, and it supports HTTP, WebSockets, and TCP with automatic SSL and custom domains.
### Can I run in more than one region?
Suga gives you a global edge with single-region compute today. All public HTTPS traffic is served through Cloudflare's global network for TLS, CDN, WAF, and DDoS protection, while your workloads run in one region per organization, chosen when you set the organization up. Regions are offered across North America, Europe and Australia, and the picker shows which are currently accepting new organizations. If you need a single organization to span multiple regions today, reach out and we'll set it up manually. If multi-region compute is a hard requirement now, a platform like Fly.io leads here.
## Pricing and Trust
### Is Suga production-ready?
Suga runs production workloads, and the reliability features are in place: zero-downtime deploys, safe rollouts that keep your running version live if a deploy fails, self-healing failover, and one-click rollback. We ship quickly and give advance notice before any breaking change. Live status is at [status.suga.app](https://status.suga.app).
### How much does Suga cost?
Suga has three tiers. **Free** is \$0 with no credit card. **Pro** is \$20 per seat per month, which includes \$20 of hosting credits per seat (pooled across your org), up to 20 projects, environment forking, and email support. **Enterprise** is custom-priced and adds SSO/SAML, audit logs, bring-your-own-cluster, and SLAs. On Suga Cloud you then pay usage-based rates for what you run, metered per second across CPU, memory, storage, and egress, and the included hosting credits cover the underlying compute for typical small workloads. Full details on [suga.app/pricing](https://suga.app/pricing).
### What does the free tier include?
The free tier includes 1 project, 1 environment, and 1 team member, with 0.1 vCPU, 256 MiB of memory, 1 GB of storage, and 1 replica. It comes with zero-downtime deploys, automatic HTTPS, the global CDN, logs and metrics, and community support, and requires no credit card.
Two things are worth knowing before you plan around it. Free services can run Suga's approved template images or an image built from your own GitHub repository, but not an arbitrary image from a registry. Free services are also limited to 5 Mbit/s of outbound bandwidth, so large responses are slower than on a paid plan. Both lift when you upgrade. See [Plan Limits](/reference/limits) for the full picture.
### Am I locked in?
No, Suga runs standard Docker containers and standard open-source databases like Postgres, Redis, and MariaDB, so there's no proprietary runtime holding your app hostage. We're the team behind the open-source Nitric framework for cloud-portable applications. The same containers can be redeployed elsewhere if you ever need to leave, and Enterprise customers can run Suga against a Kubernetes cluster they own.
### What happens to my apps and data if Suga shuts down?
Your apps stay portable because they run as standard Docker containers backed by standard database images, so you can redeploy the same containers and migrate your data using ordinary database tools anywhere else, with no proprietary format to convert away from. For larger files, we recommend external object storage like S3 or R2, which lives outside the platform and stays under your control.
### Is Suga secure?
Suga applies security by default, with per-environment network isolation, a managed WAF, always-on DDoS protection, secrets encrypted at rest, and automatic TLS at both the Cloudflare edge and the origin. WAF rules are managed by Suga and are not customer-configurable today. Origin traffic is authenticated with mutual TLS so requests cannot bypass the edge. Services are private unless you explicitly expose them.
### What languages and frameworks can I run?
Suga supports effectively any stack, because anything that runs in a Docker container runs on Suga. That includes Node.js, Bun, Deno, TypeScript, Python, Go, Rust, Ruby, and PHP, frameworks like Next.js, React, Vue, Angular, Svelte, Astro, Django, FastAPI, Flask, Laravel, and Rails, and databases including PostgreSQL, Redis, MongoDB, MySQL, and MariaDB. It also runs tools like n8n and WordPress, and supports Deno-based functions natively. If your team already works with it, you can ship it on Suga.
### Who builds Suga?
We're Nitric Inc., an infrastructure-automation company. We also maintain the open-source [Nitric framework](https://nitric.io) for cloud-portable applications.
# Side Projects
Source: https://docs.suga.app/support/side-projects
How Suga fits solo developers, indie SaaS founders, and small side projects.
> If you're building a larger team workload, the [main FAQ](/support/faq) covers backend services, comparisons, and enterprise concerns. For pricing details, see [suga.app/pricing](https://suga.app/pricing).
## Common Problems
### Why do small projects outgrow basic hosting so quickly?
Small projects outgrow basic hosting the moment they need more than one piece, because the second you add a worker, a database, a queue, or a static frontend, basic hosts either don't support it or charge per app, and the cracks show up as cold starts, opaque logs, missing rollback, and manual TLS. The fix is to start on a platform that treats your whole app (containers, databases, networking, CDN) as one unit on a single canvas, with the production safety built in from day one, so you don't have to migrate the moment your side project starts to matter.
### How portable is my app between providers?
Your container is portable, but the configuration around it usually is not. Most providers wrap a standard container in proprietary glue: custom YAML schemas, vendor-specific build configs, bespoke networking models, and their own secrets and DNS handling, so moving a workload means rewriting all of that. Suga sidesteps this by running plain Docker containers with standard Postgres, Redis, and MariaDB images and a canvas-based config that maps cleanly to what the underlying infrastructure already understands, so the same container can be redeployed elsewhere if you ever need to leave.
### Can I keep my whole app in one place?
Yes. One platform runs your containers from a Git repo, hosts databases and persistent volumes alongside them, and serves static sites through the same CDN, so the whole app lives on one canvas with one bill and one set of logs. In practice you push your repo, drag a database onto the canvas, expose a service over HTTPS, and Cloudflare's global edge serves your static frontend automatically, with no separate accounts for DNS, TLS, monitoring, or CDN to manage.
## Picking a Platform
### Is Suga appropriate for a SaaS side project?
Suga is a strong pick for small SaaS side projects because you can ship a full stack (frontend, backend, database) without YAML, Kubernetes, or a Dockerfile, with HTTPS, a CDN, a WAF, and DDoS protection wired in by default. The Pro plan includes \$20 of hosting credits with every seat (pooled across your org), which is typically enough to cover a small indie SaaS workload inside the seat fee, with credits left over as you grow.
### Is Suga manageable on my own?
Suga is built for solo developers because there's no YAML, no Kubernetes, no Dockerfile required, and no separate accounts for CDN, TLS, DNS, or logging, so a single developer can take a repo to a live HTTPS URL in a few minutes. You wire your services visually on a canvas instead of editing manifests, observability and rollback are on out of the box, and security defaults like network isolation, a WAF, and DDoS protection are applied automatically, so you don't spend evenings configuring infrastructure instead of shipping product.
### What will a side project cost me?
Suga is affordable for indie developers because its Pro plan is \$20 per seat per month and that \$20 already includes \$20 of hosting credits, so a solo developer running a typical small SaaS is effectively paying for the platform alone while the hosting sits inside the credit pool. The free tier (\$0, no credit card) gets you 1 project, 0.1 vCPU, 256 MiB of memory, and 1 GB of storage, which is enough to try a small side project end-to-end before you decide whether to upgrade.
### Can I run several side projects on one account?
For multiple side projects, Suga's Pro plan lets you run up to 20 projects on a single \$20 per seat per month seat, so a developer juggling several SaaS experiments can host them all under one account, one bill, and one canvas without paying per app or per service. Hosting credits (\$20 per seat, pooled across the org) cover the underlying compute, memory, and egress, so as long as your projects stay small, they share the same credit pool rather than each adding a fixed monthly fee on top.
### Does this fit a GitHub-based workflow?
Yes. Connect a repository and a branch, and every push to that branch builds a new image, runs it on the canvas, and serves it over HTTPS through Cloudflare's edge. Each deploy is tied back to the commit message and author, so the history tells you what changed and who changed it, and any earlier state is one click away.
### How do I deploy straight from a Git repo?
Connect the repository and Suga detects how to build it, or uses your Dockerfile if you have one. It then runs the container on the canvas and exposes an HTTPS URL through Cloudflare's global edge. You can point Suga at your source repo, import a `docker-compose.yml` to stand up a multi-service project in one step, or on a paid plan bring a pre-built image from any registry, with rollback to any previous environment state in a click.
### Can I run containers, databases, and a static site together?
Suga handles containers, databases, and static sites on a single canvas, so you can run a backend container, attach a PostgreSQL, Redis, or MariaDB database, and host a static frontend (running in a small container behind Cloudflare's CDN) all in one place. Everything connects by service name with automatic private networking, observability is wired in across all three, and a single rollback restores the entire environment configuration (services, env vars, networking, resources) in a click, which is the part most hobbyist hosting setups never quite manage to do.
# Troubleshooting
Source: https://docs.suga.app/support/troubleshooting
Common issues and solutions
This guide covers common issues you might encounter when using Suga and how to resolve them. If you don't find your issue here, [contact support](/support/contact).
## Quick Diagnosis
Before diving into specific issues, try these steps:
Look at the deployment status in your canvas. Is it Pending, Running, or Failed?
Click on your service and open the **Logs** tab. It shows everything your service wrote to stdout and stderr, including startup errors.
Double-check your environment variables, port numbers, and resource limits.
Open the service's **Status** tab and look at CPU and memory usage to see if you're hitting resource limits.
If possible, test your Docker image locally with `docker run` to verify it works.
***
## Deployment Issues
### ImagePullBackOff
**Problem:** Deployment fails with `ImagePullBackOff` or `ErrImagePull` error.
**Symptoms:** Error message says "image not found" or "manifest unknown"
**Solutions:**
* Verify the image name is spelled correctly
* Check that the tag exists in your registry
* Try pulling the image locally: `docker pull your-image:tag`
* Make sure you're not using `latest` tag if you haven't pushed it
**Symptoms:** Image exists but Suga can't pull it
**Solutions:**
* Select the service and open its **Config** tab, then expand **Registry credentials**
* Add your username and password or access token
* Make sure the image URI includes the registry host, since Suga reads the host from it:
* Docker Hub: no prefix needed, e.g. `myuser/myapp:v1`
* GHCR: `ghcr.io/myuser/myapp:v1`
* GCR: `gcr.io/my-project/myapp:v1`
* ECR: `[account-id].dkr.ecr.[region].amazonaws.com/myapp:v1`
* Apply after adding credentials
**Symptoms:** Image pulls but won't run, especially on Apple Silicon
**Solutions:**
* Rebuild your image for linux/amd64:
```bash theme={null}
docker build --platform linux/amd64 -t your-image:tag .
```
* Push the rebuilt image
* Redeploy in Suga
**Symptoms:** Timeout or network errors
**Solutions:**
* Verify the registry is online
* Check if registry requires VPN or IP allowlisting
* Try pulling from a different network
* For self-hosted registries, ensure they're publicly accessible or BYOC cluster has access
***
### CrashLoopBackOff
**Problem:** Container starts but immediately crashes, then restarts repeatedly.
**Symptoms:** Logs show error messages or exceptions
**Solutions:**
* Check logs for the actual error message
* Common issues:
* Missing environment variables
* Database connection failures
* Port binding errors
* Missing dependencies
* Test your image locally with same environment variables:
```bash theme={null}
docker run -e VAR1=value1 -e VAR2=value2 your-image:tag
```
**Symptoms:** Logs show "command not found" or immediate exit
**Solutions:**
* Verify your Dockerfile's CMD or ENTRYPOINT is correct
* If overriding command in Suga, make sure it's a valid command
* Test locally: `docker run your-image:tag`
* Common mistake: forgetting to copy the binary or script into the image
**Symptoms:** Error about port already in use or can't bind to port
**Solutions:**
* Make sure your application binds to `0.0.0.0`, not `localhost`:
```javascript theme={null}
// Good
app.listen(3000, '0.0.0.0');
// Bad
app.listen(3000, 'localhost');
```
* Verify the port in the **Public Networking** section matches your app's listening port
* Don't use privileged ports (1-1024) unless necessary
**Symptoms:** Errors about missing libraries, modules, or files
**Solutions:**
* Verify all dependencies are installed in your Dockerfile
* For Node.js: `RUN npm install` or `RUN npm ci`
* For Python: `RUN pip install -r requirements.txt`
* For compiled languages: Include runtime dependencies
* Test your image locally to ensure everything is included
**Symptoms:** OOMKilled (Out of Memory) in logs
**Solutions:**
* Increase memory allocation in Config → Resources
* Check the Status tab to see actual memory usage, then set the limit above the peak
* On the Free plan memory is capped at 256 MiB, so a service that needs more has to move to a paid plan
* Optimize your application's memory usage
***
### Deployment Stuck in Pending
**Problem:** Deployment remains in "Pending" state and doesn't progress.
**Symptoms:** Deployment pending for several minutes
**Solutions:**
* Your plan may be at resource limits
* Check total CPU/memory across all services in environment
* Delete unused services or environments to free resources
* Upgrade plan for more resources
**Symptoms:** Service with volume stuck in pending
**Solutions:**
* Verify volume is connected properly on canvas
* Check that mount path is valid (starts with `/`)
* Ensure service has only 1 replica (volumes don't work with >1)
* Try disconnecting and reconnecting the volume
**Symptoms:** Large Docker image, pending for a while
**Solutions:**
* Be patient - large images (>1 GB) take time to pull
* Check logs for "Pulling image" messages
* Consider optimizing image size:
* Use multi-stage builds
* Use Alpine-based images
* Remove unnecessary files
* Use .dockerignore
***
## Networking Issues
### Can't Access Public HTTPS Endpoint
**Problem:** Deployment succeeded but can't reach the service at the Suga URL.
**Symptoms:** Connection refused or 502 Bad Gateway
**Solutions:**
* Verify the port in the **Public Networking** section matches your app's listening port
* Check logs: look for "Server listening on port X"
* Common ports: 3000 (Node.js), 8000 (Python), 8080 (Java/Go)
* Update the port in **Config** tab → **Public Networking**
* Apply after changing the port
**Symptoms:** App starts successfully but not accessible
**Solutions:**
* Ensure your app binds to `0.0.0.0` (all interfaces), not `localhost`:
```javascript theme={null}
// Node.js/Express
app.listen(3000, '0.0.0.0');
```
```python theme={null}
# Python/FastAPI
uvicorn.run(app, host="0.0.0.0", port=8000)
```
```go theme={null}
// Go
http.ListenAndServe("0.0.0.0:8080", nil)
```
* Rebuild and redeploy with the fix
**Symptoms:** Was accessible briefly, now not
**Solutions:**
* Check runtime logs for errors
* Look for crashes, exceptions, or OOM (Out of Memory) kills
* Check the Status tab for resource usage spikes
* Increase resources if hitting limits
***
### Long-Lived Connection Drops
**Problem:** WebSocket, Server-Sent Events stream, or database connection drops every few minutes.
**Symptoms:** Connection closes after \~5 minutes of inactivity (HTTPS) or \~15 minutes (TCP Proxy)
**Solutions:**
* WebSockets: send a ping frame every 1–2 minutes
* SSE: emit `: keepalive\n\n` or a heartbeat event every 1–2 minutes
* TCP Proxy clients: enable `SO_KEEPALIVE` or a protocol-level keepalive (e.g. PostgreSQL `keepalives_idle`)
* See [Connection Timeouts](/configure/networking#connection-timeouts) for full details
**Symptoms:** Connection closes without warning, no idle pattern
**Solutions:**
* Suga Cloud closes connections whose peer has gone away (network partition, crashed client) within \~2.5 minutes
* Have the client reconnect with backoff
* Check client-side network conditions and crash logs
***
### Can't Connect to Other Services
**Problem:** Service can't connect to database or other services in same environment.
**Symptoms:** DNS errors, connection refused, host not found
**Solutions:**
* Use the service name as hostname, not the full Suga URL
* Format: `service-name:port`
* Example: `postgres:5432`, not a public URL like `k3f9x2mq7p1a-production-a1b2c3d4.us-central1.suga.run`
* The hostname is set in **Config** tab → **Private Networking** → **Hostname**. It is a DNS-safe version of the display name, so it may differ from what you see on the canvas
* Use lowercase and hyphens for multi-word names
**Symptoms:** Connection refused on specific port
**Solutions:**
* Verify the target service's port
* Common ports:
* PostgreSQL: 5432
* MySQL/MariaDB: 3306
* Redis: 6379
* MongoDB: 27017
* Check the target service's logs to see what port it's listening on
**Symptoms:** Connection refused or timeout when connecting
**Solutions:**
* Check if target service is fully running and healthy
* Look at deployment status on canvas
* Database services may take 30-60 seconds to fully start
* Implement retry logic in your application
**Symptoms:** Persistent connection timeouts
**Solutions:**
* Private networking should work automatically within same environment
* Verify both services are in the same environment
* Check logs for network-related errors
* Contact support if issue persists
***
### Custom Domain Not Working
**Problem:** Custom domain doesn't resolve to your application.
**Symptoms:** Domain doesn't resolve or goes to wrong place
**Solutions:**
* DNS propagation can take 1-48 hours
* Check DNS with: `dig your-domain.com` or `nslookup your-domain.com`
* Verify CNAME record points to your Suga domain
* Correct format:
* Type: CNAME
* Name: the subdomain you're adding, e.g. `www`
* Value: the exact target Suga showed you when you added the domain. It contains a hash, so you cannot type it from memory
* Lower TTL (300-600 seconds) for faster updates
**Symptoms:** Domain resolves to wrong place or not at all
**Solutions:**
* Log into your DNS provider (Cloudflare, Namecheap, GoDaddy, etc.)
* Verify CNAME record exists and is correct
* Should point to the target Suga gave you, not to your generated URL
* Don't include `https://` in CNAME value
* Don't add trailing dot unless required by provider
**Symptoms:** "Not Secure" warning or certificate error
**Solutions:**
* Certificate issuance can take 5-15 minutes
* Verify DNS is correctly pointing to Suga
* Clear browser cache and try again
* Check domain in incognito/private window
* Contact support if certificate doesn't issue within 1 hour
**Symptoms:** Root domain (example.com) doesn't work, only www works
**Solutions:**
* Apex domains require ANAME or ALIAS records (not all DNS providers support)
* Options:
1. Use www subdomain instead
2. Use DNS provider that supports ANAME/ALIAS (Cloudflare, DNSimple, DNS Made Easy)
3. Set up redirect from apex to www
* CNAME records cannot be used for apex domains (DNS limitation)
***
## Resource Issues
### Out of Memory (OOMKilled)
**Problem:** Container crashes with `OOMKilled` in logs.
**Symptoms:** Application crashes under load or during specific operations
**Solutions:**
* Increase memory in Config → Resources
* Start with doubling current limit (512 MiB → 1 GiB → 2 GiB)
* Watch the Status tab after the increase to see actual usage
* Some applications need more memory during startup
* Consider memory requirements of your framework/runtime
**Symptoms:** Memory usage grows over time, eventually crashes
**Solutions:**
* Profile your application for memory leaks
* Look for:
* Unclosed database connections
* Event listeners not removed
* Growing caches without limits
* Large objects kept in memory
* Implement connection pooling with max limits
* Add memory limits to in-memory caches
**Symptoms:** OOMKilled during specific operations (file uploads, exports, etc.)
**Solutions:**
* Stream large files instead of loading entirely into memory
* Process data in chunks/batches
* Use temporary files for large operations
* Increase memory limit for data-intensive operations
* Consider offloading heavy processing to separate service
***
### High CPU Usage
**Problem:** CPU usage constantly near 100% or application is slow.
**Symptoms:** The Status tab shows CPU usage at or near the limit
**Solutions:**
* Increase CPU in Config → Resources
* Watch the Status tab after the increase
* Consider horizontal scaling (replicas) for web apps
**Symptoms:** CPU high even with low traffic
**Solutions:**
* Profile your application to find bottlenecks
* Common issues:
* Synchronous blocking operations
* Inefficient algorithms
* Missing database indexes
* N+1 query problems
* Not using caching
* Optimize hot code paths
* Add caching for expensive operations
**Symptoms:** CPU usage correlates with request volume
**Solutions:**
* Scale horizontally by increasing replicas
* Config tab → Replicas: 2, 3, or more
* Load balancing happens automatically
* Add caching (Redis) for frequently accessed data
* Optimize database queries
* Consider CDN for static assets
***
### Disk Space Issues
**Problem:** Application can't write files or "disk full" errors.
**Symptoms:** Can't persist files, data lost on restart
**Solutions:**
* Services have small ephemeral storage (not persistent)
* Create a Volume and add it to the canvas
* Connect volume to your service
* Set mount path (e.g., `/data`, `/app/uploads`)
* Update your app to write to the mount path
* Redeploy
**Symptoms:** "No space left on device" error
**Solutions:**
* Check disk usage in logs: `df -h /data`
* Delete old or unnecessary files
* Implement log rotation
* Clean up temporary files
* Volume size limits vary by plan. See [Plan Limits](/reference/limits#volume-limits) for tier caps
**Symptoms:** Files seem to write but disappear on restart
**Solutions:**
* Verify you're writing to the mounted volume path
* Example: If volume mounted at `/data`, write to `/data/file.txt`
* Don't write to root filesystem locations unless on volume
* Check volume connection on canvas
* Verify the mount path in the Volumes tab
***
## Function-Specific Issues
### Function Timeout
**Problem:** Deno function times out before completing.
**Symptoms:** Function timeout error in logs
**Solutions:**
* Functions have limited execution time
* Optimize slow operations:
* Use database indexes
* Limit query results
* Cache expensive computations
* Process data in smaller chunks
* For long-running tasks, use a Container service instead
**Symptoms:** Timeout when calling external services
**Solutions:**
* Set shorter timeouts on external HTTP calls
* Implement retry logic with exponential backoff
* Cache results when possible
* Consider async processing for slow operations
***
## Volume Issues
### Can't Mount Volume
**Problem:** Volume won't connect to service or deployment fails with volume error.
**Symptoms:** Error about replicas when mounting volume
**Solutions:**
* Volumes cannot be mounted to services with >1 replica
* Reduce replicas to 1 in Config tab → Replicas
* This is a fundamental limitation (prevents data corruption)
* For scalable apps needing storage, use:
* External database service
* Object storage (S3-compatible)
* Shared filesystem (coming soon)
**Symptoms:** Volume in use or locked error
**Solutions:**
* Each volume can only be mounted to one service
* Disconnect volume from other service first
* Create separate volumes for different services
* Check canvas for existing volume connections
**Symptoms:** Error about mount path during deployment
**Solutions:**
* Mount path must be absolute (start with `/`). That is the only rule Suga enforces
* Use a dedicated subdirectory: `/data`, `/app/storage`, `/var/lib/postgresql/data`
* Mounting over a directory the image already uses, such as `/etc` or `/usr`, is allowed but hides the image's own files there and usually breaks the container. Pick a path your image does not need
***
### Volume Data Lost
**Problem:** Data in volume disappeared or was reset.
**Symptoms:** All data gone, volume shows as new
**Solutions:**
* Deleting a volume permanently deletes data (no recovery)
* Check deployment history to see if volume was deleted
* Restore from backups if available
* Implement regular backup strategy going forward
**Symptoms:** Data disappears after restart
**Solutions:**
* Verify application writes to correct mount path
* Check logs for actual file paths being used
* Data written outside mount path is ephemeral (lost on restart)
* Update application to use mounted volume path
**Symptoms:** Volume exists but no data visible
**Solutions:**
* Check volume is connected on canvas
* Verify mount path in service config
* Check logs for volume mounting errors
* Redeploy to remount volume
***
## Account and Billing Issues
### Can't Log In
**Problem:** Unable to access Suga dashboard.
**Symptoms:** "Invalid email or password" error
**Solutions:**
* Verify email address is correct
* Try password reset: Click "Forgot Password"
* Check caps lock is off
* Try different browser or incognito mode
* Clear browser cache and cookies
**Symptoms:** "No account found" error
**Solutions:**
* Verify you signed up (check email for confirmation)
* Try signing up again if no confirmation received
* Check spam folder for activation email
* Contact support at [support@suga.app](mailto:support@suga.app)
**Symptoms:** SAML or SSO errors
**Solutions:**
* Contact your organization admin
* Verify SSO configuration in organization settings
* Try using email/password instead (if enabled)
* Contact support for SSO troubleshooting
***
### Billing or Plan Issues
**Problem:** Issues with subscription, billing, or plan limits.
**Symptoms:** Can't create more projects/environments, resource allocation fails
**Solutions:**
* Review plan limits in the Billing page in the left sidebar
* Delete unused resources to free up quota
* Upgrade plan for higher limits
**Symptoms:** Billing error, services suspended
**Solutions:**
* Check payment method in the Billing page in the left sidebar
* Verify card is not expired
* Check sufficient funds available
* Update payment method
* Contact support if issue persists: [support@suga.app](mailto:support@suga.app)
**Symptoms:** Want to switch from Pro to Free
**Solutions:**
* First reduce resources to fit Free plan limits:
* Max 1 project
* Max 1 environment
* Delete extra resources
* Then request downgrade in the Billing page in the left sidebar
* Or contact [support@suga.app](mailto:support@suga.app)
**Symptoms:** Need billing documentation
**Solutions:**
* Go to the Billing page in the left sidebar
* Download PDF invoices for past months
* Invoices include all charges and payment details
* For custom invoices or tax forms, email [support@suga.app](mailto:support@suga.app)
***
## Getting More Help
If you can't find a solution here:
Get help from community and team
Contact [support@suga.app](mailto:support@suga.app)
Report bugs and request features
### What to Include When Asking for Help
To get faster support, include:
* **Project name** and organization name
* **Environment name** (production, staging, etc.)
* **Service name** affected
* **Complete error messages** from logs
* **Steps to reproduce** the issue
* **When it started** happening
* **What you've already tried**
* **Screenshots** if applicable
The more details you provide, the faster we can help resolve your issue.
***
## Debugging Checklist
When troubleshooting, work through this checklist:
Is the service Running, Pending, or Failed? Look at the canvas status.
Click service → **Logs**. This is everything your service wrote to stdout and stderr, including startup. Filter by level to find errors quickly, or select **Open in Logs explorer** for the full view.
Check all settings in the **Config** and **Env Vars** tabs: variables, ports, resources, networking.
Click service → **Status**. Look for resource exhaustion (CPU or memory at limits).
Verify networking: can you reach HTTPS endpoint? Can services connect to each other?
Did the issue start after a deployment? Check deployment history and consider rollback.
Pull and run your Docker image locally with same config to isolate the issue.
Start with the logs - they usually contain the exact error message that points to the solution.
# Deploy a Docker Compose App
Source: https://docs.suga.app/tutorials/deploy-docker-compose
Deploy your docker-compose.yml on Suga, with automatic HTTPS, cross-container secret references, and managed volumes.
[Docker Compose](https://docs.docker.com/compose/) is a tool for defining and running multi-container Docker applications using a simple YAML configuration file.
This guide explains how to deploy a project using a Docker Compose file in two ways:
1. [Step-by-step via the canvas](#deploy-using-the-canvas)
2. [Using a coding agent](#deploy-using-an-agent)
The examples in this guide deploy a self-hosted [n8n](https://n8n.io/) with Postgres. If you have your own project, follow the same steps with your own compose file. If not, use this example to follow along:
```yaml docker-compose.yml expandable theme={null}
services:
postgres:
image: postgres:18-alpine
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: n8n
volumes:
- postgres_data:/var/lib/postgresql/data
n8n:
image: docker.n8n.io/n8nio/n8n:latest
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: "5432"
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
GENERIC_TIMEZONE: ${GENERIC_TIMEZONE:-UTC}
N8N_HOST: ${N8N_HOST:-localhost}
N8N_PROTOCOL: ${N8N_PROTOCOL:-http}
WEBHOOK_URL: ${WEBHOOK_URL:-http://localhost:5678/}
ports:
- "5678:5678"
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
volumes:
postgres_data:
n8n_data:
```
## Deploy using the Canvas
In the Suga dashboard, click **New project**, then **Create empty project**. Suga creates the project along with a default `production` environment; the canvas opens automatically.
Right-click empty space on the canvas and choose **Add → Import Compose**. Paste your
compose file. Suga adds a container for each service, wired with the images,
env vars, ports, and named volumes from the file. For the example file,
that's two containers: postgres and n8n.
Select the container that needs a public URL. On its **Config** tab, in the
**Public Network** section, click **Add Endpoint → HTTPS Domain** and choose
the service's port. Suga reserves a hostname immediately and shows the URL in
the properties panel. For the example, add the endpoint to the n8n container
on port 5678.
Import resolves `${VAR}` shell placeholders for you: variables shared between services (like a database password) arrive as cross-container references, and `${VAR:-default}` defaults are applied. What's left is swapping any localhost-style defaults for your Suga hostname.
For the example file, update the n8n container's env vars:
* `N8N_HOST`: choose **Reference**, pick `n8n` → `SUGA_PUBLIC_HOSTNAME`.
* `WEBHOOK_URL`: set to `https://{{n8n.SUGA_PUBLIC_HOSTNAME}}/`. The `{{...}}` picker inserts the reference alongside literal text.
* `N8N_PROTOCOL`: set to the literal `https`.
The canvas now has both containers with their volumes attached:
And the n8n container's env vars panel shows the references you wired:
Import marks secret-looking env vars (passwords, keys, tokens) as **Sensitive**, but they still need real values. Click each value cell and provide one. The example file has two, which you can generate with `openssl rand -hex 32`:
* `POSTGRES_PASSWORD` on the postgres container.
* `N8N_ENCRYPTION_KEY` on the n8n container. n8n uses this to encrypt credentials it stores in the database.
Save both values somewhere secure, you'll want them later.
Click **Apply** in the top right of the canvas. Suga rolls your containers out. For the example app, n8n's first-run screen loads at the public URL a few seconds later.
## Deploy using an Agent
To deploy with a coding agent such as [Claude Code](https://claude.com/product/claude-code), [Codex](https://openai.com/codex/), or [OpenCode](https://opencode.ai/), follow these steps:
If you haven't already, connect your agent to the [Suga MCP server](/agents/mcp).
From the directory containing your compose file, ask your agent to deploy your application to Suga.
Here's a basic prompt you can use:
```markdown Prompt icon="sparkles" wrap expandable theme={null}
Using the docker compose file from this project, deploy my app with the Suga MCP server.
Ask which organization to use and create a new project for this deployment.
Add each service as a container. For env vars shared between services (like a database password), reference the source container's variable instead of duplicating.
For env vars that need the app's public URL (host, base URL, webhook URL), reference `SUGA_PUBLIC_HOSTNAME` on the container with the public endpoint, and set any protocol/scheme env vars to `https`.
Leave passwords, keys, and tokens blank and marked sensitive.
```
The agent will give you a link to the new environment on the Suga canvas. Open it to review the setup.
Env vars marked **Sensitive** need values before you can deploy. Select each container with sensitive variables, open its **Env Vars** tab, click each value input, and provide a value.
The example file has two, which you can generate with `openssl rand -hex 32`:
* `POSTGRES_PASSWORD` on the postgres container.
* `N8N_ENCRYPTION_KEY` on the n8n container. n8n uses this to encrypt credentials it stores in the database.
Save both values somewhere secure, you'll want them later.
Click **Apply** in the top right. Suga rolls your containers out. For the example app, n8n's first-run screen loads at the public URL a few seconds later.
## What gets imported
Suga maps each field in your Compose file to its closest equivalent. Most fields import directly; a few aren't needed on Suga, and a few need a small change.
Each service becomes a container on the canvas. The service name becomes the container's private hostname.
Public registries work as-is; private registries need credentials set up once.
Values pass through, and `${VAR}` placeholders are resolved: a variable shared between services imports as a cross-container reference, `${VAR:-default}` defaults are applied, and names that look like secrets (passwords, keys, tokens) are marked **Sensitive** automatically.
Combined into the container's start command, Docker-style: entrypoint first, command as its arguments.
Container ports become private ports; host ports are skipped. Add an HTTPS endpoint to the service that needs a public URL.
Mounted at the same path. Persists across restarts, redeploys, and rollbacks.
CPU and memory limits and reservations carry over to the container's resource settings, and `replicas` sets the instance count (services with volumes stay at 1).
These fields aren't needed on Suga. Keep them for local dev or remove them; import ignores them either way.
Services start together; app-level retries handle boot order.
Every environment has one private network, and services reach each other by hostname. No configuration needed.
Suga restarts failed containers automatically.
`container_name`, `labels`, `logging`, `profiles`, `healthcheck`, and similar fields are also safely ignored.
These fields aren't imported and may need a small change:
`./host:/path` mounts are skipped. Use a named volume for persistent state, or bake seed files into the image.
A service with only a `build:` and no `image` is skipped entirely. Publish the image to a registry first, or add the container manually and connect a build repository.
Inline the values under `environment` instead.
Use **Sensitive** env vars (encrypted at rest) instead, and cross-container references to share a value between containers.
## FAQ
Services with a `build:` directive and no `image` are skipped on import. Add
a container for that service manually, then connect a build repository under
**Image → Build from GitHub**. Point it at the same source; Suga uses the
Dockerfile you specify or auto-detects the project. Every push to the watched
branch rebuilds and rolls the service forward.
No. Once imported, the Suga environment is the source of truth. Keep the
Compose file in-repo for local dev if you want.
Yes. The Compose file works locally as before. Import reads it once; it
doesn't stay linked to your Suga environment.
References use the syntax `{{.variables.KEY}}`, where the container id is the short resource id Suga assigns at creation. Set the value on one container and reference it from others. Suga's own system variables (like `SUGA_PUBLIC_HOSTNAME`) work the same way.
For seed data or config baked into the repo, copy the file into the container image with a small custom `Dockerfile` layer or a build-repo commit. For persistent state, use a named volume in the Compose file instead of a bind mount, and Suga imports it as a managed volume.
# Deploy FastAPI with Postgres on Suga
Source: https://docs.suga.app/tutorials/deploy-fastapi-postgres
Deploy a FastAPI app on Suga with a private Postgres database, automatic builds from GitHub, and a public HTTPS URL.
[FastAPI](https://fastapi.tiangolo.com/) apps deploy on Suga straight from a GitHub repo, with Postgres running alongside as a private container. Suga detects the Python install and start commands automatically, so no Dockerfile is needed.
This guide explains how to deploy a FastAPI app with Postgres in two ways:
1. [Step-by-step via the canvas](#deploy-using-the-canvas)
2. [Using a coding agent](#deploy-using-an-agent)
Your repo needs an ASGI entry point (usually `main.py` exposing `app = FastAPI(...)`) and a `requirements.txt` listing `fastapi`, an ASGI server (`uvicorn`), and a Postgres driver (`psycopg` or `psycopg2`), plus any ORM or migration tooling you use.
## Deploy using the Canvas
In the Suga dashboard, click **New project** and pick your FastAPI repo from the GitHub list, installing the Suga GitHub App if prompted. On the import page, name the project, set the branch you want deployed, and leave the build method on auto-detect; Suga detects the Python install and start commands. See [Import from a GitHub repository](/concepts/projects#import-from-a-github-repository) for the full set of import options.
Click **Create project**. Suga opens the canvas with the app service already connected to your repo.
Right-click empty space on the canvas, choose **Add → Template**, and pick **PostgreSQL**. Suga prompts for `POSTGRES_USER` and `POSTGRES_DB` (both default to `postgres`) and pre-fills a generated `POSTGRES_PASSWORD`.
Copy the password now, it won't be visible after creation.
Suga adds the postgres container with port 5432 private and a volume mounted at `/var/lib/postgresql/data`.
Select the app service. On its **Config** tab, in the **Private Network** section, set the port to `8000`. Then, in the **Public Network** section, click **Add Endpoint → HTTPS Domain** and choose port 8000.
On the app container, add a `DATABASE_URL` env var. Set the value to a connection string with an embedded reference to Postgres's password:
```
postgresql://postgres:{{postgres.variables.POSTGRES_PASSWORD}}@postgres:5432/postgres
```
The `{{...}}` picker inserts the reference alongside literal text, so the app reads the password from postgres at deploy time without duplicating it. Swap the user and database name if you changed them from the defaults.
Add any other secrets your app needs (JWT signing keys, API keys) as **Sensitive** env vars on the app container, then click **Apply** in the top right.
Suga clones the app repo, installs dependencies, starts the ASGI server on port 8000, and rolls out both containers. The FastAPI app is served at the public URL and reaches Postgres privately at `postgres:5432`. Hit the root URL and you'll see:
```json theme={null}
{"hello":"suga"}
```
## Deploy using an Agent
To deploy with a coding agent such as [Claude Code](https://claude.com/product/claude-code), [Codex](https://openai.com/codex/), or [OpenCode](https://opencode.ai/), follow these steps:
If you haven't already, connect your agent to the [Suga MCP server](/agents/mcp).
Ask your agent to deploy your repo to Suga. Here's a basic prompt you can use, with your repo and branch filled in:
```markdown Prompt icon="sparkles" wrap expandable theme={null}
Deploy this FastAPI app on Suga with a Postgres database, using the Suga MCP.
Repo: Branch:
Ask which organization to use and create a new project for this deployment. Add two containers:
- postgres: image `postgres:18-alpine`, private on port 5432. Set `POSTGRES_USER` and `POSTGRES_DB` to something matching the app name. Leave `POSTGRES_PASSWORD` blank and marked sensitive. Add a volume mounted at `/var/lib/postgresql/data`.
- the app container: no image, private port 8000, public HTTPS endpoint on 8000. Connect the repo as the build source (auto-detect, no Dockerfile).
On the app container, set `DATABASE_URL` to `postgresql://:{{.variables.POSTGRES_PASSWORD}}@postgres:5432/` so the app reads the password from postgres without duplication.
```
The agent will give you a link to the new environment on the Suga canvas. Open it to review the setup.
Set `POSTGRES_PASSWORD` on the postgres container: click the value input and paste a value generated with `openssl rand -hex 32`. If your app has other secrets (JWT signing keys, API keys), add them to the app container as **Sensitive** env vars.
Save the postgres password somewhere secure, you'll want it later.
Click **Apply** in the top right. Suga clones the app repo, installs dependencies, starts the ASGI server on port 8000, and rolls out both containers. The FastAPI app is served at the public URL and reaches Postgres privately at `postgres:5432`. Hit the root URL and you'll see:
```json theme={null}
{"hello":"suga"}
```
## FAQ
No. Suga detects Python from `requirements.txt` or `pyproject.toml` and runs the standard install and start flow. If you already have a Dockerfile, you can tell the agent to use it instead; otherwise Suga's auto-detect handles the common case.
Any version. Suga uses the version pinned in `.python-version`, `runtime.txt`, or your `pyproject.toml` if present, and falls back to a recent LTS release.
Pass `RAILPACK_START_CMD` as a build arg on the app container with your exact command, for example `uvicorn app.main:app --host 0.0.0.0 --port 8000` or `gunicorn -k uvicorn.workers.UvicornWorker app.main:app`. The default only works when your entry point matches the standard `main:app` pattern.
Wrap the start command with the migration: pass `RAILPACK_START_CMD=alembic upgrade head && uvicorn main:app --host 0.0.0.0 --port 8000` as a build arg. The migration runs each time a new container boots.
Yes. Swap the `postgres:18-alpine` container for a MySQL, MariaDB, or MongoDB image (or any container that runs the database you want). Adjust `DATABASE_URL` and the driver in your `requirements.txt` to match.
Configure pool size in SQLAlchemy or your driver directly. For a shared external pool, add PgBouncer as a third container on the canvas and point `DATABASE_URL` at it instead of postgres directly.
The managed volume persists across restarts, redeploys, and rollbacks. For point-in-time recovery or off-site backups, run `pg_dump` on a schedule from another container, or point the app at a managed Postgres service instead of a container.
The Free tier fits a small FastAPI plus Postgres stack, including the build history and volume. Pro is per-seat with hosting credits that offset compute and storage. Full pricing at [suga.app/pricing](https://suga.app/pricing).
# Deploy an MCP server on Suga
Source: https://docs.suga.app/tutorials/deploy-mcp-server
Host an MCP server on Suga with a public HTTPS URL, automatic builds from GitHub, and OAuth-ready env vars for AI agent access.
An [MCP server](https://modelcontextprotocol.io/) that speaks streamable HTTP deploys on Suga as a single container with a public HTTPS URL, built straight from your GitHub repo.
This guide explains how to deploy an MCP server in two ways:
1. [Step-by-step via the canvas](#deploy-using-the-canvas)
2. [Using a coding agent](#deploy-using-an-agent)
Your repo needs an HTTP server that mounts an MCP handler at a known path (`/mcp` is conventional), plus your language's standard build files (`package.json`, `requirements.txt` or `pyproject.toml`, `go.mod`, and so on). Any MCP SDK works.
## Deploy using the Canvas
In the Suga dashboard, click **New project** and pick your MCP server repo from the GitHub list, installing the Suga GitHub App if prompted. On the import page, name the project, set the branch you want deployed, and leave the build method on auto-detect. See [Import from a GitHub repository](/concepts/projects#import-from-a-github-repository) for the full set of import options.
Click **Create project**. Suga opens the canvas with a service already connected to your repo.
Select the service. On its **Config** tab, in the **Private Network** section, set the port to whatever your server listens on (typically `3000` or `8000`). Then, in the **Public Network** section, click **Add Endpoint → HTTPS Domain** and choose the same port. Suga reserves a hostname immediately and shows the URL in the properties panel. This URL plus your server's route (like `/mcp`) is what clients will connect to.
If your server uses OAuth or calls out to third-party APIs, add the client secrets and API keys as **Sensitive** env vars on the container first. Then click **Apply** in the top right. Suga clones the repo, installs dependencies, starts the server, and rolls the container out.
Connect a client to the public URL from the properties panel, plus your server's route. In Claude Code:
```bash theme={null}
claude mcp add --transport http https:///mcp
```
Run `/mcp` in the session and the tools your server exposes show up.
## Deploy using an Agent
To deploy with a coding agent such as [Claude Code](https://claude.com/product/claude-code), [Codex](https://openai.com/codex/), or [OpenCode](https://opencode.ai/), follow these steps:
If you haven't already, connect your agent to the [Suga MCP server](/agents/mcp).
Ask your agent to deploy your repo to Suga. Here's a basic prompt you can use, with your repo, branch, and port filled in:
```markdown Prompt icon="sparkles" wrap expandable theme={null}
Deploy this MCP server on Suga using the Suga MCP.
Repo: Branch:
Server port:
Ask which organization to use and create a new project for this deployment.
Add a container named after the repo, private on that port, with a public HTTPS endpoint on the same port. Connect the repo as the build source (auto-detect, no Dockerfile).
```
The agent will give you a link to the new environment on the Suga canvas. Open it to review the setup.
If your server uses OAuth or calls out to third-party APIs, add the client secrets and API keys as **Sensitive** env vars on the container first. Then click **Apply** in the top right. Suga clones the repo, installs dependencies, and starts the server.
Connect a client to the public URL from the container's properties panel, plus your server's route. In Claude Code:
```bash theme={null}
claude mcp add --transport http https:///mcp
```
Run `/mcp` in the session and the tools your server exposes show up.
## FAQ
No. Suga detects the language from the standard project files (`package.json`, `requirements.txt`, `go.mod`, etc.) and runs the right install and start commands. Bring a Dockerfile if you need custom system dependencies; otherwise auto-detect handles the common case.
Any. If your server runs in a container that speaks HTTP on a port, Suga runs it. Node with `@modelcontextprotocol/sdk`, Python with `mcp`, Go, Rust, and any custom implementations all work the same way.
Yes. Suga's public HTTPS endpoint forwards long-lived connections to your container, so an MCP server speaking streamable HTTP is reachable at the public URL the moment it starts. No extra configuration needed for streaming or SSE.
OAuth is a server-side concern: implement the flow in your MCP server (the `@modelcontextprotocol/sdk` and Python `mcp` packages both have OAuth helpers), then set the provider config and client secrets as env vars on the container. Suga stores sensitive values encrypted at rest and never exposes them in the UI.
Yes. Any client that supports remote MCP servers over HTTP can connect at the public URL. Claude Code uses `claude mcp add --transport http`, Cursor adds an entry to `mcp.json`, Claude Desktop uses **Add custom connector**, and ChatGPT connectors accept the URL directly.
In-container sessions live in the container's memory, so with more than one replica each instance keeps its own. For a shared session store, add a Redis container on the canvas and point your server at it using a cross-container reference for the password.
Yes. When configuring the container, set the build context to the MCP server's subdirectory, or pass `RAILPACK_BUILD_CMD` and `RAILPACK_START_CMD` as build args to target the specific server.
Yes. Attach a memorable domain like `mcp.example.com` to the container in the dashboard once the server is deployed.
The Free tier fits a small MCP server and its build history. Pro is per-seat with hosting credits that offset compute and storage. Full pricing at [suga.app/pricing](https://suga.app/pricing).
# Deploy Next.js on Suga
Source: https://docs.suga.app/tutorials/deploy-nextjs
Deploy a Next.js app to Suga from a GitHub repo, with automatic builds, a public HTTPS URL, and build-time or runtime env vars.
[Next.js](https://nextjs.org/) apps deploy on Suga straight from a GitHub repo. Suga detects `next build` and `next start` from your `package.json`, so no Dockerfile is needed.
This guide explains how to deploy a Next.js app in two ways:
1. [Step-by-step via the canvas](#deploy-using-the-canvas)
2. [Using a coding agent](#deploy-using-an-agent)
If you have your own Next.js repo, follow the steps with it. If not, scaffold a fresh app and push it to a GitHub repo to follow along:
```bash theme={null}
npx create-next-app@latest hello-suga --typescript --app --tailwind --eslint
```
## Deploy using the Canvas
In the Suga dashboard, click **New project** and pick your Next.js repo from the GitHub list, installing the Suga GitHub App if prompted. On the import page, name the project and leave the build method on auto-detect; Suga picks up `next build` and `next start` from your `package.json`. Set the branch you want deployed, and a root directory if the app lives in a subdirectory. See [Import from a GitHub repository](/concepts/projects#import-from-a-github-repository) for the full set of import options.
Click **Create project**. Suga opens the canvas with a service already connected to your repo.
Select the service. On its **Config** tab, in the **Private Network** section, set the port to `3000` (Next.js's default). Then, in the **Public Network** section, click **Add Endpoint → HTTPS Domain** and choose port 3000. Suga reserves a hostname immediately and shows the URL in the properties panel.
Click **Apply** in the top right. Suga clones the repo, runs `next build`, and starts the app. A fresh Next.js app takes 60-90 seconds end to end.
The default Next.js landing page loads at the public URL.
## Deploy using an Agent
To deploy with a coding agent such as [Claude Code](https://claude.com/product/claude-code), [Codex](https://openai.com/codex/), or [OpenCode](https://opencode.ai/), follow these steps:
If you haven't already, connect your agent to the [Suga MCP server](/agents/mcp).
Ask your agent to deploy your repo to Suga. Here's a basic prompt you can use, with your repo and branch filled in:
```markdown Prompt icon="sparkles" wrap expandable theme={null}
Deploy this Next.js repo on Suga using the Suga MCP.
Repo: Branch:
Ask which organization to use and create a new project for this deployment.
Add a container named after the repo with a private port and a public HTTPS endpoint, and connect the repo as the build source (auto-detect, no Dockerfile).
Check next.config.* for the port: static export is served on 80, next start on 3000. Don't assume 3000.
Then prove it works: fetch the public URL and confirm the HTML and its JS/CSS assets actually load. A 200 alone doesn't prove it.
```
The agent will give you a link to the new environment on the Suga canvas. Open it to review the setup.
Click **Apply** in the top right. Suga clones the repo, runs `next build`, and starts the app. Your app loads at the public URL 60-90 seconds later.
## FAQ
No. Suga detects Next.js from `package.json` and runs the right build and start commands. If you already have a Dockerfile, you can tell the agent to use it instead; otherwise Suga's default handles the standard flow.
Any version. Suga runs the version pinned in your `package.json`, both the pages router and the app router. Node.js version comes from `engines` in `package.json` or a `.nvmrc` file if you have one.
Add them as **build args** on the container, not as regular env vars. Build args are set during the build, which is when Next.js inlines `NEXT_PUBLIC_*` values into the client bundle. Runtime env vars are only visible on the server after the build finishes.
Yes. They run on the same container as the rest of the app in the Node.js runtime. No separate function service or edge runtime configuration is needed.
Yes. Next.js's built-in image optimization runs on the container using the default `sharp`-based loader. No extra configuration required. For a CDN-backed loader, configure it in `next.config.js` as usual.
ISR and the data cache work in-container. Regenerated pages and cached fetches live on the container's local disk, so with more than one replica each instance keeps its own copy. For cross-instance persistence, add a Redis service on the canvas and point the cache at it.
Yes. When configuring the container, set the build context to your Next.js subdirectory, or pass `RAILPACK_BUILD_CMD` and `RAILPACK_START_CMD` as build args to target the specific app.
Yes. Attach your domain to the container in the dashboard once the app is deployed.
The Free tier fits a small Next.js app plus its build history. Pro is per-seat with hosting credits that offset compute and storage. Full pricing at [suga.app/pricing](https://suga.app/pricing).
# Deploy Rails with Postgres on Suga
Source: https://docs.suga.app/tutorials/deploy-rails-postgres
Deploy a Ruby on Rails app on Suga with a private Postgres database, automatic builds from GitHub, and a public HTTPS URL.
[Ruby on Rails](https://rubyonrails.org/) apps deploy on Suga straight from a GitHub repo, with Postgres running alongside as a private container. Suga detects the Ruby install and start commands from your `Gemfile`, so no Dockerfile is needed.
This guide explains how to deploy a Rails app with Postgres in two ways:
1. [Step-by-step via the canvas](#deploy-using-the-canvas)
2. [Using a coding agent](#deploy-using-an-agent)
Your repo needs a standard Rails layout: a `Gemfile` listing `rails`, `puma`, and `pg`, a `Gemfile.lock`, and the usual `config/`, `app/`, and `bin/` folders.
The guide assumes `config/database.yml` reads `DATABASE_URL` in the production section (Rails' default template does), Puma is your web server, and `db:prepare` handles migrations.
## Deploy using the Canvas
In the Suga dashboard, click **New project** and pick your Rails repo from the GitHub list, installing the Suga GitHub App if prompted. On the import page, name the project, set the branch you want deployed, and leave the build method on auto-detect; Suga detects the Ruby install and start commands. See [Import from a GitHub repository](/concepts/projects#import-from-a-github-repository) for the full set of import options.
Click **Create project**. Suga opens the canvas with the app service already connected to your repo.
Right-click empty space on the canvas, choose **Add → Template**, and pick **PostgreSQL**. Suga prompts for `POSTGRES_USER` and `POSTGRES_DB` (both default to `postgres`) and pre-fills a generated `POSTGRES_PASSWORD`.
Copy the password now, it won't be visible after creation.
Suga adds the postgres container with port 5432 private and a volume mounted at `/var/lib/postgresql`.
Select the app service. On its **Config** tab, in the **Private Network** section, set the port to `3000`. Then, in the **Public Network** section, click **Add Endpoint → HTTPS Domain** and choose port 3000.
On the app container, add a `DATABASE_URL` env var. Set the value to a connection string with an embedded reference to Postgres's password:
```
postgres://postgres:{{postgres.variables.POSTGRES_PASSWORD}}@postgres:5432/postgres
```
The `{{...}}` picker inserts the reference alongside literal text, so the app reads the password from postgres at deploy time without duplicating it. Swap the user and database name if you changed them from the defaults.
Then add three literal env vars so Rails runs in production mode without a separate log or static-file server:
* `RAILS_ENV`: `production`
* `RAILS_LOG_TO_STDOUT`: `true`
* `RAILS_SERVE_STATIC_FILES`: `true`
Add `SECRET_KEY_BASE` as a **Sensitive** env var on the app container (generate one with `bundle exec rails secret` or `openssl rand -hex 64`). If your app uses encrypted credentials, add `RAILS_MASTER_KEY` instead, matching the contents of `config/master.key`. Then click **Apply** in the top right.
Suga clones the app repo, runs `bundle install`, starts Puma on port 3000, and rolls out both containers. The Rails app is served at the public URL and reaches Postgres privately at `postgres:5432`. Hit the root URL and you'll see:
```json theme={null}
{"hello":"suga"}
```
## Deploy using an Agent
To deploy with a coding agent such as [Claude Code](https://claude.com/product/claude-code), [Codex](https://openai.com/codex/), or [OpenCode](https://opencode.ai/), follow these steps:
If you haven't already, connect your agent to the [Suga MCP server](/agents/mcp).
Ask your agent to deploy your repo to Suga. Here's a basic prompt you can use, with your repo and branch filled in:
```markdown Prompt icon="sparkles" wrap expandable theme={null}
Deploy this Rails app on Suga with a Postgres database, using the Suga MCP.
Repo: Branch:
Ask which organization to use and create a new project for this deployment. Add two containers:
- postgres: image `postgres:18-alpine`, private on port 5432. Set `POSTGRES_USER` and `POSTGRES_DB` to something matching the app name. Leave `POSTGRES_PASSWORD` blank and marked sensitive. Add a volume mounted at `/var/lib/postgresql`.
- the app container: no image, private port 3000, public HTTPS endpoint on 3000. Connect the repo as the build source (auto-detect, no Dockerfile).
On the app container:
- Set `DATABASE_URL` to `postgres://:{{.variables.POSTGRES_PASSWORD}}@postgres:5432/`.
- Set `RAILS_ENV=production`, `RAILS_LOG_TO_STDOUT=true`, `RAILS_SERVE_STATIC_FILES=true` as literal values.
- Set `RAILPACK_START_CMD` build arg to `bundle exec rails db:prepare && bundle exec rails server -b 0.0.0.0 -p 3000` so migrations run before Puma starts.
```
The agent will give you a link to the new environment on the Suga canvas. Open it to review the setup.
Set `POSTGRES_PASSWORD` on the postgres container: click the value input and paste a value generated with `openssl rand -hex 32`. On the app container, add `SECRET_KEY_BASE` as a **Sensitive** env var (generate one with `bundle exec rails secret`), or `RAILS_MASTER_KEY` matching your `config/master.key` if you use encrypted credentials.
Save both values somewhere secure, you'll want them later.
Click **Apply** in the top right. Suga clones the app repo, runs `bundle install`, applies migrations, starts Puma on port 3000, and rolls out both containers. The Rails app is served at the public URL and reaches Postgres privately at `postgres:5432`. Hit the root URL and you'll see:
```json theme={null}
{"hello":"suga"}
```
## FAQ
No. Suga detects Ruby from your `Gemfile` and runs the standard install and start flow. If you already have a Dockerfile, you can tell the agent to use it instead; otherwise auto-detect handles the common case.
Any version. Suga uses the version pinned in your `Gemfile` (`ruby "x.y.z"`), `.ruby-version`, or `.tool-versions` if present, and falls back to a recent stable release.
Pass `RAILPACK_START_CMD` as a build arg on the app container with your exact command. Common alternatives: `bundle exec puma -C config/puma.rb` for a custom Puma config, `bundle exec unicorn -c config/unicorn.rb -p 3000` for Unicorn, `bundle exec passenger start -p 3000` for Passenger, or `bundle exec thin -p 3000` for Thin. Suga only cares that something listens on the container's private port.
Wrap the start command with `db:prepare`: pass `RAILPACK_START_CMD=bundle exec rails db:prepare && bundle exec rails server -b 0.0.0.0 -p 3000` as a build arg. `db:prepare` creates the database if it doesn't exist and applies pending migrations, so it's safe on first boot and idempotent afterward.
Yes. Drop the `bundle exec rails db:prepare && ` prefix from `RAILPACK_START_CMD` and run migrations manually — from the container's shell in the dashboard, or from your CI pipeline before you Apply. Running migrations at boot is convenient, but teams with strict migration workflows often prefer to trigger them explicitly.
Use `bundle exec rails db:create db:migrate` instead: pass `RAILPACK_START_CMD=bundle exec rails db:create db:migrate && bundle exec rails server -b 0.0.0.0 -p 3000` as a build arg. `db:create` no-ops if the database already exists, so it's safe to run on every boot.
Add `RAILS_MASTER_KEY` as a **Sensitive** env var on the app container, with the value matching your local `config/master.key`. Rails reads it at boot to decrypt `config/credentials.yml.enc`, so anything referenced from `Rails.application.credentials` becomes available.
Yes. Suga runs `bundle exec rails assets:precompile` as part of the build when it detects an `app/assets/` directory or the `sprockets-rails` gem. Precompiled assets are baked into the image, so `RAILS_SERVE_STATIC_FILES=true` is enough to serve them without a separate nginx.
Set `RAILPACK_BUILD_CMD` as a build arg on the app container to run the JavaScript build followed by `assets:precompile`. Examples: `bundle exec rails javascript:build && bundle exec rails assets:precompile` for `jsbundling-rails` (esbuild, rollup, or bun), `bundle exec vite build && bundle exec rails assets:precompile` for `vite_rails`, or `bundle exec rails webpacker:compile && bundle exec rails assets:precompile` for Webpacker. Precompiled output lands in `public/assets/` and `RAILS_SERVE_STATIC_FILES=true` serves it.
Yes. Add each database as its own postgres container on the canvas, and set an env var per connection matching what your `config/database.yml` reads (e.g. `PRIMARY_DATABASE_URL`, `REPLICA_DATABASE_URL`). Reference each container's `POSTGRES_PASSWORD` in the corresponding URL. The cross-container reference works for any number of databases.
Add a second app container on the canvas with the same repo but a different start command, for example `RAILPACK_START_CMD=bundle exec sidekiq`. Set the same `DATABASE_URL` and any Redis env vars, and leave it with no public endpoint. Add a Redis container from the template for the Sidekiq broker.
The managed volume persists across restarts, redeploys, and rollbacks. For point-in-time recovery or off-site backups, run `pg_dump` on a schedule from another container, or point the app at a managed Postgres service instead of a container.
Yes. Attach your domain to the app container in the dashboard once the app is deployed.
The Free tier fits a small Rails plus Postgres stack, including the build history and volume. Pro is per-seat with hosting credits that offset compute and storage. Full pricing at [suga.app/pricing](https://suga.app/pricing).
# Why Suga?
Source: https://docs.suga.app/why-suga
Rethinking infrastructure deployment from first principles
For years, deploying infrastructure has meant choosing between two paradigms, each with fundamental trade-offs.
Traditional Infrastructure as Code (Terraform, Pulumi, CloudFormation) gives you version control, reproducibility, and audit trails. You know who changed what and when. Environments can be recreated from configuration. But deployments are slow, often taking multiple minutes. YAML and HCL files grow complex. The learning curve is steep.
Cloud console interfaces (AWS Console, GCP Console, Azure Portal) let you move quickly. Click, configure, deploy. No config files to manage. But changes vanish without trace. There's no review process before modifications go live. Environments drift apart. You lose track of who changed what.
Most teams pick one paradigm and accept its limitations. Fast iteration or infrastructure discipline. Not both.
## Rethinking Infrastructure Deployment
Suga started by asking: what do teams actually need?
They need speed. Deployment times measured in seconds, not minutes. Fast iteration cycles that don't break flow state. The ability to test changes quickly and tear them down when done.
They need safety. Version control for infrastructure changes. Audit trails showing who deployed what and why. The ability to review modifications before they go live. Instant rollback when problems appear.
They need clarity. A way to see what they're building. Understanding how services connect and depend on each other. Architecture that documents itself.
They need reproducibility. Environments that can be cloned for testing. The confidence that staging matches production. Infrastructure that doesn't drift over time.
Suga achieves all of this simultaneously. Every deployment is tracked with a commit message, author, and timestamp. Environments can be cloned, copied entirely for isolated testing. Deployment history is complete; you can roll back to any previous state. The canvas shows your architecture visually, making connections and dependencies explicit.
And deployments are fast. Not because we skipped the safety checks, but because we rethought how deployment pipelines work.
## The Abstraction Question
Every major advance in computing has been built on abstraction. SQL didn't make databases harder to manage. It made them accessible to millions of developers who didn't need to understand B-tree algorithms. Python didn't make programs harder to debug. It made development faster by abstracting away register management and memory allocation.
The key is that good abstractions don't hide complexity; they manage it. They provide the right interface for the task at hand while still allowing you to drop lower when needed.
Suga treats Kubernetes the same way Python treats assembly language: as an implementation detail, not the interface. You work with services, deployments, and environments. Kubernetes handles the orchestration. For most tasks, you shouldn't need to think about Kubernetes internals.
This makes infrastructure more debuggable, not less. Instead of running kubectl commands, you open unified logs across all services. Instead of parsing YAML to understand architecture, you see it on the canvas. The complexity is still there (Kubernetes is still running your workloads), but it's been organized so you can reason about it clearly. We didn't remove the beast. We just taught it to behave.
## What This Means for You
Your team needs to test a new feature. Clone your production environment. The entire stack (services, databases, configuration) copies to a new isolated environment. Deploy your changes. Test them. Review the results. Tear down the environment when you're done. No one else's work was affected.
A deployment goes wrong. You notice the error rate spiking. Open deployment history, select the previous version, apply it as a draft, and apply. Your services roll back. The bad deployment stays in history so you can see exactly what changed and who deployed it.
You're debugging a production issue but can't reproduce it in staging. Clone production to a new environment. You now have an exact copy where you can experiment safely. Check logs, modify configuration, narrow down the problem. The original production environment stays untouched.
Your infrastructure changes are tracked. Six months from now, someone asks "when did we add Redis?" The deployment history shows the commit, the author, and the message explaining why. The architecture diagram shows how it connects to other services.
## When to Use Suga
You want the version control, audit trails, and reproducibility of Infrastructure as Code, but you're frustrated with slow deployment cycles and YAML complexity. Suga gives you both: infrastructure discipline with fast deployments.
Your team ships frequently and needs quick feedback loops. But you also need to know who deployed what and when. Suga tracks every change while keeping deployment times measured in seconds.
You're running dev, staging, and production environments and need them to stay consistent. Clone environments for testing. Review changes before promoting them. Keep environments reproducible without manual configuration.
The visual canvas makes infrastructure concepts concrete. See how services connect. Understand networking and dependencies. The audit trail shows you exactly what changed with each deployment.
If your application requires specific Kubernetes configurations (custom schedulers, specialized network policies, or unusual resource types), you need more control than Suga Cloud gives you. Running Suga against a cluster you own is available on Enterprise, see [Bring Your Own Cluster](/reference/byoc-kubernetes).
## What to Expect
Suga is under active development. We ship quickly, so some capabilities are still being built and interfaces may change. We'll give advance notice before breaking changes. Join our [Discord](https://suga.app/chat) for the latest.
## What's Coming
These features are on the roadmap:
* **Environment Management**: Additional Git-like operations for environment workflows
* **Preview Environments**: Automatic environments for every pull request
* **Autoscaling**: Scale replicas automatically based on CPU and memory usage
* **Volume Backups**: Automated snapshots with point-in-time recovery
* **Public API**: REST API for CI/CD automation and infrastructure as code
* **More Regions**: Additional geographic regions for lower latency
* **Alerting**: Email and Slack notifications for deployment failures and resource issues
Want to influence our roadmap? [Join the discussion on Discord](https://suga.app/chat) or [open an issue on GitHub](https://github.com/sugasrc/suga/issues).
## Next Steps
Ready to give Suga a try?
Deploy in 5 minutes
Sign up for free
Service templates and settings
Understand the platform