# Paste a Dockerfile or Compose file
URL: https://synquic.tech/docs/guides/deploy-dockerfile-or-compose.md

Deploy without a repository by writing a Dockerfile or pasting a docker-compose.yml in the panel. Covers what the build can see, ports, environment variables and .env files, and what to do after the first deploy.

import { Step, Steps } from 'fumadocs-ui/components/steps';

Sometimes all you have is a recipe: a Dockerfile that downloads and builds an app, or a
`docker-compose.yml` from a project's README. The **Dockerfile** and **Compose** tabs deploy exactly that,
with no repository and no folder to upload. You paste the file, Synq stores it as the project's source,
builds or pulls what it describes, and runs it on your server.

| Tab | You give Synq | Synq does |
|---|---|---|
| **Dockerfile** | One Dockerfile | Builds an image from it and runs one container. |
| **Compose** | One `docker-compose.yml` (and an optional `.env`) | Pulls each service's image and runs them together as a stack. |

Both tabs are on the **New Project** page (sidebar **New Project**). Deep links: `/library#dockerfile` and
`/library#compose`.

## Deploy a pasted Dockerfile

<Steps>

<Step>

### Open the Dockerfile tab

The card is titled **Deploy from a Dockerfile** ("Write or paste a Dockerfile. Synq builds the image and
runs it."). The editor starts with a small working example:

```dockerfile
FROM nginx:alpine
RUN echo '<h1>Hello from Synq</h1>' > /usr/share/nginx/html/index.html
EXPOSE 80
```

</Step>

<Step>

### Write or paste your Dockerfile

Replace the example with your own. It needs at least one `FROM` line ("The Dockerfile needs a FROM
instruction."). Remember that **the Dockerfile is the whole build context**: there are no other files next
to it, so `COPY` and `ADD` have nothing local to copy. Fetch the code inside the build instead:

```dockerfile
FROM node:22-alpine
RUN apk add --no-cache git
WORKDIR /app
# Fetch the app's code during the build
RUN git clone --depth 1 https://github.com/acme/hello-node.git . \
 && npm ci --omit=dev
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "server.js"]
```

`ADD https://...` (a remote URL) and `RUN curl ...` work too. `COPY --from=<image>` works for copying out of
another image.

</Step>

<Step>

### Name it and check the port

- **Project name**: required, and unique in your organization.
- **Container port**: the port the app listens on inside the container. It follows the Dockerfile's last
  `EXPOSE` line as you type (80 when there is none), until you change it by hand.

</Step>

<Step>

### Pick the server and add variables

- **Server**: which server builds and runs it.
- **Environment variables** (optional): one `KEY=value` per line. They are set on the running container
  **and** passed to the build as build arguments, so a Dockerfile `ARG APP_VERSION` receives the value of
  an `APP_VERSION=...` line.

</Step>

<Step>

### Press Build and deploy

Synq uploads the Dockerfile ("Uploading…"), creates the project, and starts the first build
("Deploying…"). You land on the build screen with the live `docker build` output. When it is live, add a
domain on the project's **Domains & Routes** tab.

</Step>

</Steps>

### After the first deploy

- **Redeploy** rebuilds the same Dockerfile. With `git clone` or `curl` in it, that fetches the code again.
- The project is a Dockerfile project: the image's own `CMD` starts the app, and the port is the
  **Container port** you set (change it later on the **Configuration** tab).
- There is no editor for the stored Dockerfile. To change it, create a new project from this tab, or put
  the new Dockerfile in a folder and run `synq deploy --folder --project <project-id>` there to deploy that
  folder to the existing project (or link the folder first with `synq init`; see
  [Deploy a local folder](/docs/guides/deploy-local-folder#cli)).
- For code that changes often, use a repository instead ([GitHub](/docs/guides/deploy-from-github) or
  [any Git URL](/docs/guides/deploy-from-git-url)): a repo Dockerfile is built with the whole repository as
  context, and pushes can redeploy it automatically.

## Deploy a pasted Compose file

<Steps>

<Step>

### Open the Compose tab

The card is titled **Deploy from a Compose file** ("Paste a docker-compose.yml. Synq deploys each of its
services."). The editor starts with a one-service example:

```yaml
services:
  web:
    image: nginx:alpine
    ports:
      - "80"
    restart: unless-stopped
```

</Step>

<Step>

### Paste your docker-compose.yml

The file needs a top-level `services:` block with at least one service. Under the editor, Synq lists the
services it found ("Services: web, db") as you type. Two rules:

- **Every service uses `image:`**. A service with `build:` has no files to build from here, because only
  the Compose file is uploaded. Push the image to a registry first, or use a repository instead.
- **Indent with spaces.** YAML does not allow tabs ("YAML cannot be indented with tabs. Use spaces.").

A typical stack:

```yaml
services:
  app:
    image: ghcr.io/acme/app:2.3.0
    environment:
      DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
    ports:
      - "3000"
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: app
    volumes:
      - db_data:/var/lib/postgresql/data
volumes:
  db_data: {}
```

Services reach each other by service name (`db` above), never `localhost`.

</Step>

<Step>

### Add the .env values

**Environment variables (.env)** takes one `KEY=value` per line:

```bash
DB_PASSWORD=change-me-to-something-long
```

Synq saves them twice: as a `.env` file next to the Compose file, so `${VAR}` references and
`env_file: .env` resolve, and as project variables you can edit later on the **Environment** tab.

</Step>

<Step>

### Name it, pick the server, press Deploy stack

Enter a **Project name** (required, unique), choose the **Server**, and press **Deploy stack**. Synq
uploads the file, parses it on the server ("No services were found in this Compose file." means the server
could not read any service), creates the project, and deploys every service. You land on the build screen.

</Step>

</Steps>

### After the first deploy

- Open the project's **Apps & Services** tab to see one row per service. A service with ports is not public
  until you give it a domain: expose it and set a domain on **Domains & Routes**. See
  [Compose & multi-service apps](/docs/guides/compose-multi-service).
- Named volumes (like `db_data`) belong to the project and survive redeploys.
- **Redeploy** applies the stored Compose file again and pulls images as needed.
- Compose fields Synq models are listed in
  [Compose & multi-service apps](/docs/guides/compose-multi-service#1-from-a-docker-composeyml-file).

## Limits

- **Dockerfile**: a single file, no build context, one container. `COPY` and `ADD` of local paths fail.
- **Compose**: a single file plus an optional `.env`; no `build:` services, no extra config files to mount.
  Use a [repository](/docs/guides/deploy-from-git-url) or an [archive upload](/docs/guides/deploy-local-folder#upload-an-archive)
  when the stack needs its own files.
- Both create a project whose source is the uploaded file. There is no push webhook; use a
  [deploy hook](/docs/guides/deploy-hooks) to trigger redeploys from outside.

## Related

<Cards>
  <Card title="Deploy a Docker image" href="/docs/guides/deploy-docker-image" description="Run one prebuilt image, with private registry logins." />
  <Card title="Compose & multi-service apps" href="/docs/guides/compose-multi-service" description="Manage, expose and update the services of a stack." />
  <Card title="Build detection and builders" href="/docs/guides/build-detection" description="How repositories with a Dockerfile or Compose file are built." />
</Cards>
