Standard deployments overwrite files directly on your server. This is fine for most sites, but it means there's a window during every deployment where some files are new and others are old. If a visitor hits your site during that window, they may see errors — and if the deployment fails partway through, you're left with a partially updated codebase.

Atomic deployments eliminate both problems. Each deployment goes into its own directory, and your live site switches to the new release only after everything is in place. If the deployment fails, your site keeps running from the previous release, completely unaffected.

If you have an existing [DeployHQ](https://www.deployhq.com) project using standard deployments, migrating to atomic deployments requires creating a new server configuration and updating your web server settings.

## Standard vs atomic deployments

| Aspect | Standard | Atomic |
| --- | --- | --- |
| File updates | Overwrites in place | Deploys to a new directory |
| Downtime risk | Yes — during file transfer | None — symlink switch is instant |
| Failed deployment | Partially updated files | Previous release stays live |
| Rollback | Not possible without redeploying | Instant — switch symlink back |
| Disk usage | Single copy of files | 3 copies (current + 2 previous) |

## How atomic deployments work

When you run an atomic deployment, [DeployHQ](https://www.deployhq.com) creates this directory structure within your deployment path:

```
/var/www/your-app/
├── releases/
│ ├── 20260325120000/ # Previous release
│ └── 20260325140000/ # Current release
├── shared/ # Persistent files (uploads, config, logs)
│ ├── config/
│ └── storage/
├── cache/ # Build cache (if configured)
└── current -> releases/20260325140000 # Symlink to active release
```

Your web server serves content from the `current` symlink. When a new deployment completes, [DeployHQ](https://www.deployhq.com) switches `current` to point at the new release directory. This switch is an atomic filesystem operation — there's no in-between state.

```
sequenceDiagram
    participant D as DeployHQ
    participant S as Server
    participant W as Web Server

    Note over W: Serving from current → release-A
    D->>S: Create new release directory
    D->>S: Copy previous release files
    D->>S: Upload changed files
    D->>S: Symlink shared files
    D->>S: Switch current → release-B
    Note over W: Now serving from current → release-B
```

## Migration steps

### 1. Identify files outside your repository

Before migrating, check what's on your server that isn't in your Git repository. Common examples:

- **Configuration files** : `.env`, `config/database.yml`, `wp-config.php`
- **User uploads** : `uploads/`, `storage/app/public/`
- **Log files** : `storage/logs/`, `log/`
- **Cache directories** : `cache/`, `tmp/`

These need to be moved into the `shared` directory after the atomic deployment structure is created.

### 2. Create a new server in DeployHQ

In your [DeployHQ](https://www.deployhq.com) project, add a new server with the same connection details as your existing one (hostname, username, credentials). On the configuration screen, check the **Perform zero-downtime deployments on this server** option.

**Important** : The deployment path you specify must be empty. [DeployHQ](https://www.deployhq.com) needs a clean directory to create the `releases/`, `shared/`, and `current` structure. If your current site lives at `/var/www/your-app/`, you have two options:

1. **Use a new parent directory** (e.g., `/var/www/your-app-atomic/`) and update your web server configuration
2. **Back up and clear the existing directory** , then use the same path

### 3. Run a full deployment

[Deploy](https://www.deployhq.com) to the new server. [DeployHQ](https://www.deployhq.com) creates the directory structure and uploads a complete copy of your codebase to the first release directory.

### 4. Move persistent files to shared

SSH into your server and move any files that need to persist across releases into the `shared` directory:

```
# Example: move uploads directory
mv /var/www/your-app-atomic/releases/20260325120000/storage/app/public \
   /var/www/your-app-atomic/shared/storage/app/public

# Example: move environment file
cp /var/www/old-site/.env /var/www/your-app-atomic/shared/.env
```

[DeployHQ](https://www.deployhq.com) automatically symlinks everything in `shared/` into each new release during deployment. The directory structure must match — a file at `shared/config/database.yml` gets symlinked to `releases/TIMESTAMP/config/database.yml`.

### 5. Update your web server configuration

Point your web server's document root to the `current` symlink:

**Nginx:**

```
server {
    root /var/www/your-app-atomic/current/public;
    server_name example.com;
    # ... rest of your configuration
}
```

**Apache:**

```
DocumentRoot /var/www/your-app-atomic/current/public
<Directory /var/www/your-app-atomic/current/public>
    Options FollowSymLinks
    AllowOverride All
</Directory>
```

Reload your web server configuration:

```
sudo systemctl reload nginx
# or
sudo systemctl reload apache2
```

### 6. Remove the old server from DeployHQ

Once you've confirmed the atomic deployment is working correctly, remove the old (standard) server from your [DeployHQ](https://www.deployhq.com) project.

## Troubleshooting common migration issues

### Permission denied when creating symlinks

Ensure the deployment user has write permissions to the entire deployment path. The user needs to create directories, copy files, and create symlinks.

### Shared files not appearing in releases

Check that the shared directory structure matches where the application expects the files. If your app expects `config/database.yml`, the file must be at `shared/config/database.yml`.

Also verify that the shared files don't exist in your Git repository. If they do, [DeployHQ](https://www.deployhq.com) can't create the symlink because the file is already there. Add these files to your `.gitignore`.

### Application errors after switching

If your application throws errors after the switch, it may be related to:

- **Cached paths** : Some frameworks cache absolute file paths. Clear the application cache as an SSH command after deployment
- **Missing shared files** : Double-check that all necessary config and upload directories are in `shared/`
- **Process restarts** : If your app runs a persistent process (like a [Node.js server](https://www.deployhq.com/blog/using-nodejs-and-npm-with-deployhq-build) or PHP-FPM), you may need to restart it via an SSH command

### Running out of disk space

[DeployHQ](https://www.deployhq.com) keeps 3 releases (current + 2 previous). For large codebases, ensure your server has at least 3x the disk space of your application. [DeployHQ](https://www.deployhq.com) automatically cleans up older releases.

## Combining with build pipelines

If your project uses a [build pipeline](https://www.deployhq.com/blog/the-deployhq-build-pipeline) (for compiling assets, installing dependencies, etc.), it works seamlessly with atomic deployments. The build runs before files are transferred, and the compiled output goes into the new release directory.

## Combining with SSH commands

For applications that need [database migrations](https://www.deployhq.com/blog/how-do-you-handle-database-changes-during-a-deployment) or process restarts, configure SSH commands to run after files are transferred. The commands run in the context of the new release directory, before the symlink is switched.

* * *

Ready to eliminate deployment downtime? [Sign up for DeployHQ](https://www.deployhq.com/signup) and set up atomic deployments in minutes.

If you have any questions about migrating to atomic deployments, contact us at [support@deployhq.com](mailto:support@deployhq.com) or reach out on [X (Twitter)](https://x.com/deployhq).

