# Deploy a folder or archive
URL: https://synquic.tech/docs/guides/deploy-local-folder.md

Put an app online straight from a folder on your computer or a .zip or tar archive (.tar, .tar.gz, .tar.bz2, .tar.xz, .tar.zst), with no Git repository. The browser upload, the archive upload, and the one-command CLI way, with size limits and what gets skipped.

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

Not everything lives in a Git repository. Sometimes the code is a folder on your laptop, a download, or an
archive someone sent you. Synq can take that folder or archive, work out what is inside, build it, and give
you back a running app. No Git remote needed.

<Callout title="What you need first">
- Synq up and running (you can open the panel). If not, start with [Installation](/docs/getting-started/installation).
- A folder or an archive with your app in it: a website, an API, anything.
- You do **not** need Docker or any special files. Synq reads the source and works out the rest (see
  [Build detection](/docs/guides/build-detection)).
</Callout>

## Three ways in

| Way | Where | Best for |
|---|---|---|
| **Folder** upload | **New Project → Folder** in a browser | A project folder on the computer you are using. |
| **Archive** upload | **New Project → Archive** | A `.zip`, `.tar`, `.tar.gz`/`.tgz`, `.tar.bz2`, `.tar.xz` or `.tar.zst` you already have. |
| **CLI** | `synq deploy --folder` in a terminal | Repeat deploys of the same folder, and scripts. |

The [desktop app](/docs/getting-started/desktop-app) shows the same panel, so its **Folder** tab uploads the
folder the same way.

## Upload a folder from the browser

A browser cannot read your disk on its own, so you tell Synq what you are deploying, then hand it the
folder. It is packed **in your browser** and uploaded.

<Steps>

<Step>

### Open the Folder tab

Click **New Project** in the sidebar, then the **Folder** tab.

</Step>

<Step>

### Pick your stack

The tab asks **What are you deploying?** Choose the tile that matches your app, for example Next.js, Vite
or Express. The stack sets the build environment Synq prepares.

</Step>

<Step>

### Drop in your folder

Drag the project folder onto the drop zone, or click to browse for it. Once it is picked, you see a summary
with the folder name and how many files it contains. **Clear selection** starts over; **Back to stack
selection** changes the stack.

</Step>

<Step>

### Press Continue

Synq packs and uploads the folder (the button shows **Packing folder…**, then **Uploading…**) and opens the
[deploy screen](/docs/dashboard/deploy-wizard) with the detected settings.

</Step>

<Step>

### Press Deploy

Check the detected framework and commands, add environment variables and a domain, and press **Deploy**.
The build screen streams the logs; when it finishes, you get a link.

</Step>

</Steps>

### What gets uploaded

Only your **source**. These are left out, because the build recreates them:

- anywhere in the tree: `.git`, `node_modules`, `vendor`, `.next`, `.nuxt`, `.svelte-kit`, `.astro`,
  `.output`, `.vite`, `.turbo`, `.cache`, `.nx`, `.react-router`, `.dev-secrets.json`;
- at the top of the folder only: `dist`, `build` and `data` (the same names deeper down, such as
  `src/data`, are kept).

If everything was skipped you see "That folder looks empty (or everything was ignored). Pick a project
folder." Choose the folder that holds your `package.json` (or `go.mod`, `Cargo.toml`, `requirements.txt`,
and so on).

## Upload an archive

The **Archive** tab takes a single archive file of your app and treats its contents like an uploaded
folder.

<Steps>

<Step>

### Open the Archive tab

Click **New Project** in the sidebar, then **Archive** (or open `/library#archive`). The card is titled
**Upload an app archive**.

</Step>

<Step>

### Drop the archive

Drop a `.zip`, `.tar`, `.tar.gz` (`.tgz`), `.tar.bz2` (`.tbz2`, `.tbz`), `.tar.xz` (`.txz`) or `.tar.zst`
(`.tzst`) file on the drop zone, or click to browse. The project name is taken from the file name
(`shop-2.3.zip` becomes `shop-2.3`). **Choose another file** replaces it. 7z and rar archives are not
supported: repack the app as a `.zip` or `.tar.gz` first.

</Step>

<Step>

### Press Continue

Synq uploads the file ("Uploading…"), unpacks it on the server, and opens the deploy screen. From there it
is the same as a folder upload: check the detected build and press **Deploy**.

</Step>

</Steps>

### How the archive is unpacked

- The format is recognized from the file's contents, not only its name.
- Every tar flavor gets the same checks and limits as a `.tar.gz`: `.tar.bz2` and `.tar.xz` are
  unpacked with the server's `bzip2` and `xz` programs (included in the Synq API image), and `.tar.zst`
  with the runtime's built-in zstd. If a native install lacks one of those programs, that format is
  refused with a message naming the missing program; the other formats keep working.
- If everything in the archive sits in **one top-level folder** (the usual result of zipping a folder, or of
  GitHub's "Download ZIP"), that folder becomes the app's root. Otherwise the archive's root is used.
- The macOS `__MACOSX` folder is removed, and a stray top-level `.DS_Store` doesn't stop a single
  wrapping folder from being used as the app root.
- Unlike a folder upload, **nothing else is skipped**: remove `node_modules` and build output before
  archiving to keep the upload small.
- Symbolic links are allowed only when they point inside the archive. "Files that would land outside the
  archive, and links that leave it, are rejected."

### Archive limits

| Limit | Value |
|---|---|
| Formats | `.zip`, `.tar`, `.tar.gz`, `.tar.bz2`, `.tar.xz`, `.tar.zst` (not 7z or rar) |
| Archive file size | 300 MB |
| Unpacked size | 300 MB, whatever the compression |
| Files and folders in the archive | 100,000 |
| Zip compression | Stored or Deflate (the standard). Other methods are refused: re-create the zip with standard compression. |
| Encrypted zips | Not supported. |

Errors you may see: "Choose a .zip, .tar, .tar.gz, .tgz, .tar.bz2, .tar.xz or .tar.zst file.",
"7z and rar are not supported; repack as .zip or .tar.gz.", "This archive is larger than 300 MB.",
"Source archive contains too many entries", "Source archive exceeds its size limit", "Encrypted zip
archives are not supported", and "Source archive is empty".

## CLI

The CLI does the whole thing in one command. Run `synq deploy --folder` inside the folder to upload it. It
packages the folder, uploads it, detects the stack, creates the project (or reuses the linked one), and
deploys it, the same pipeline as the browser upload.

```bash
# From inside your project folder:
synq deploy --folder --name my-app --watch
```

- `--name` is only a fallback name. The detected name wins: the `name` field in `package.json` when the
  folder has one, otherwise a name Synq generates for the upload. To choose the project, use `synq init`
  or `--project <id>` (below).
- `--watch` follows the build logs in your terminal until it finishes. Leave it off and Synq prints a
  command to follow the logs later.
- `--server <id>` picks the server (see `synq server list`).

<Callout title="Deploying inside a Git repository?" type="info">
`--folder` uploads the files directly, even from a Git checkout. Without it, `synq deploy` in a Git
repository uses the Git flow. Outside Git, `--name` also opts into a folder upload.

Run it from your app's source directory: uploading the temporary directory, or any folder that contains
it, is refused so that staging archives never end up inside your source. If `TMPDIR` points inside your
app, set it somewhere else.
</Callout>

### Deploy to the same project again

Point the CLI at the project explicitly, or a repeat deploy can create a new project. A folder whose
`package.json` has a `name` reuses the project with that name, but a folder without one gets a new
generated name on every run.

Link the folder once with `synq init`, or pass `--project <id>` on each run:

```bash
synq init             # pick a project to link this folder to
synq deploy --folder  # uploads this folder to the linked project
synq deploy --folder --project <project-id>  # or target a project without linking
```

`synq init` writes a small `.synq/project.json` file so later commands know which project this folder
belongs to. It links to a project that **already exists**, so create one first (with a folder deploy, or
in the panel).

## After the first deploy

- **Redeploy** rebuilds the files you uploaded last time. To ship changed files, upload again (the CLI
  in a folder linked with `synq init` is the quickest), or connect a repository under **Source & Triggers → Source**
  (**Link a Repository**) so pushes can deploy.
- There is no push webhook for uploaded code. To trigger redeploys from outside, use a
  [deploy hook](/docs/guides/deploy-hooks).

## Troubleshooting

<Callout title="“That folder looks empty” when you pick it" type="warn">
Everything in the folder was on the skip list (like `node_modules` and `.git`), or you picked a folder with
no source in it. Choose the folder that contains your app's code.
</Callout>

<Callout title="The build failed" type="error">
Open the build screen and read the last few red lines; that is the real reason. First-time failures are
almost always a missing build command, a missing environment variable, or the app listening on the wrong
port. See [Troubleshooting → Deployments](/docs/troubleshooting/deployments).
</Callout>

## Related guides

<Cards>
  <Card title="Deploy from GitHub" href="/docs/guides/deploy-from-github" description="Connect a repo instead, and redeploy automatically on every push." />
  <Card title="Paste a Dockerfile or Compose file" href="/docs/guides/deploy-dockerfile-or-compose" description="Deploy from a single file, no folder needed." />
  <Card title="Environment variables" href="/docs/guides/environment-variables" description="Give your app its secrets and settings, safely." />
</Cards>
