v0.18.0
m1k1o/nekov0.18.0Apr 10, 2026by psviderski
AI Summary
Major update introducing pre-deploy hooks for database migrations, redesigning the deployment plan output, making SSH the default connection method, and adding Compose extensions for PID and shm_size.
Key Highlights
- New x-pre_deploy extension for migrations
- SSH is now the default connection method
- Redesigned deployment plan output
- Added x-context extension to pin compose files
Breaking Changes
- Requires both 'uc' and daemon to be upgraded to v0.18.0
- Default connection method changed to SSH
New Features
- Pre-deploy hooks for one-off commands
- Compose pid namespace support
- Compose shm_size support
- uc exec separator flag
Full Release Notes
The main highlights of this release are **pre-deploy hooks** for running database migrations and a **redesigned deployment plan** output that makes `uc deploy` much nicer to read and understand.
On top of that, 0.18.0 also:
- makes the system `ssh` CLI the default connection method (with fallback to the Go implementation)
- adds Compose support for `pid`, `shm_size`, and the new `x-context` extension to pin a Compose file to a cluster
- brings new docs, a bunch of quality-of-life improvements and bug fixes, read on for the full details!
## Pre-deploy hooks
⚠️ This requires both `uc` and the daemon to be [upgraded to v0.18.0](#upgrade-to-0180)
Changes: [f4581ea](https://github.com/psviderski/uncloud/commit/f4581eac1167979e9297d749cb8ac8aa56a1cecc), [1c8b770](https://github.com/psviderski/uncloud/commit/1c8b770), [772b31b](https://github.com/psviderski/uncloud/commit/772b31b), [0e820f9](https://github.com/psviderski/uncloud/commit/0e820f9)
You can now run a one-off command before deploying a service using the new `x-pre_deploy` Compose extension. This is ideal for database schema migrations, uploading static assets to a CDN, cache invalidation, and any other setup task that needs to run **once** before new code goes live.
```yaml title="compose.yaml"
services:
web:
build: ..
environment:
DATABASE_URL: postgres://postgres:${DB_PASSWORD}@db:5432/postgres
x-pre_deploy:
# Apply Django migrations from the built image before deploying new app containers.
command: python manage.py migrate
depends_on:
- db
```
Here is how it's displayed in the deploy plan when you run `uc deploy`:
<img width="692" height="115" alt="Screenshot 2026-04-10 at 5 16 56 pm" src="https://github.com/user-attachments/assets/fc921bdd-aeea-43e9-923e-abefa2426358" />
The hook command runs in a new container that inherits the service's image, environment variables, volumes, placement, and compute resources.
If the command exits successfully, the deployment continues with a normal rolling update. If it fails or times out, the deployment stops immediately and `uc deploy` displays the latest hook logs to help you diagnose the issue.

Container tables in `uc ps` and `uc inspect` now also list pre-deploy hook containers.
See the docs:
- [Pre-deploy hooks](https://uncloud.run/docs/guides/deployments/pre-deploy-hooks) guide for more details and examples
- [`x-pre_deploy`](https://uncloud.run/docs/compose-file-reference/extensions#x-pre_deploy) reference for all available attributes
## Restyled deployment plans
Changes: [0f4c211](https://github.com/psviderski/uncloud/commit/0f4c211), [f5a77b8](https://github.com/psviderski/uncloud/commit/f5a77b8), [b4b1232](https://github.com/psviderski/uncloud/commit/b4b1232)
The deployment plan output that you see when running `uc deploy`, `uc scale`, and `uc caddy deploy` has been redesigned with consistent styling, clearer operation verbs, and a header and the prompt showing the target context.
We hope this makes it easier for you to understand what changes will be made and to which cluster before you confirm the deployment.
<img width="1728" height="1093" alt="Screenshot 2026-03-18 at 9 39 38 pm" src="https://github.com/user-attachments/assets/f9d67b36-4a19-4ec6-b115-23c09b90f795" />
## System `ssh` is now the default connection method
Change: [06c2bc5](https://github.com/psviderski/uncloud/commit/06c2bc55f2fbf20920613aac45c07952107160a0)
The `ssh+cli://` connection method that uses your system's `ssh` CLI is now the default for new connections, so the prefix can be omitted:
```shell
# Old
uc machine init ssh+cli://user@host
# New
uc machine init user@host
```
`ssh_cli:` can also be replaced with just `ssh:` in the config file (`~/.config/uncloud/config.yaml`):
```yaml title="config.yaml"
contexts:
prod:
connections:
- ssh: user@host
```
This will by default use your existing SSH config, agent, keys, `ProxyJump`, and `ProxyCommand` setup automatically. You can fall back to the Go native SSH implementation using `ssh+go://` prefix.
Combined with the SSH control socket reuse introduced in [v0.17.0](https://github.com/psviderski/uncloud/releases/tag/v0.17.0), this makes most `uc` commands noticeably faster and removes a whole class of authentication friction.
The new [Connecting to a cluster](https://uncloud.run/docs/concepts/clusters/connecting) doc walks through all the supported connection schemes (`ssh://`, `ssh+go://`, `tcp://`, `unix://`), how `uc` picks a machine to talk to from your config, and how to connect without a config file for CI pipelines and scripts.
## Cluster context selection in Compose
Change: [1525d18](https://github.com/psviderski/uncloud/commit/1525d182b516b876510d6e4413ca2fe9ff029b53)
You can now pin a Compose file to a specific context using the new `x-context` extension. This prevents accidentally deploying to the wrong cluster when you switch contexts.
```yaml title="compose.yaml"
x-context: prod
services:
web:
image: myapp
```
When `x-context` is set, `uc deploy` will use that context regardless of your currently selected one in the Uncloud config. The deployment plan output also displays the target context so you always know where your changes are going.
See [`x-context`](https://uncloud.run/docs/compose-file-reference/extensions#x-context) reference for more details.
## Compose `pid` namespace support
PR: [#276](https://github.com/psviderski/uncloud/pull/276). Thanks to @miekg for the contribution ❤️
You can now configure the [PID namespace mode](https://github.com/compose-spec/compose-spec/blob/main/spec.md#pid) for service containers. The most common use case is `pid: host`, which lets a container see and interact with processes on the host. This is useful for monitoring agents, debuggers, and similar tooling.
```yaml
services:
monitoring:
image: agent
pid: host
```
## Compose `shm_size` support
Change: [8ae38cf](https://github.com/psviderski/uncloud/commit/8ae38cfd57d02f42631e0c2bb54c4331b9c072c9)
You can now set [`shm_size`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#shm_size), the size of the `/dev/shm` shared memory tmpfs. This is useful for databases like Postgres, headless Chromium, and other workloads that need a larger shared memory segment.
```yaml
services:
postgres:
image: postgres:18
shm_size: 256mb
```
## Documentation
- [Connecting to a cluster](https://uncloud.run/docs/concepts/clusters/connecting): a complete guide to cluster contexts, connection resolution and all supported types, and how to connect without a config file
- [CLI configuration file](https://uncloud.run/docs/cli-config-reference): a full reference for the `~/.config/uncloud/config.yaml` file, covering contexts, connections, and all supported fields
- [Pre-deploy hooks](https://uncloud.run/docs/guides/deployments/pre-deploy-hooks): a guide for the new feature, with examples for database migrations and other one-off setup tasks
- [Compose extensions](https://uncloud.run/docs/compose-file-reference/extensions): a dedicated reference page for all Uncloud-specific Compose extensions
## Improvements
- The `uc` CLI and the daemon now exchange versions on every gRPC call and error if they are incompatible. This is a groundwork to make better user experience when releasing breaking changes in the future ([#260](https://github.com/psviderski/uncloud/pull/260)). Thanks to @jabr for the contribution ❤️
- New `uc exec` accepts an optional `--` separator before the command, matching Docker and other CLIs ([#301](https://github.com/psviderski/uncloud/pull/301)). Thanks to @nick-potts for the contribution ❤️
- New `uc docs --manual` flag generates manual pages for `uc`, making it easier for distribution maintainers to package manpages alongside the binary ([#302](https://github.com/psviderski/uncloud/pull/302)). Thanks to @miekg for the contribution ❤️
- The daemon now exposes a gRPC method to fetch journald logs from a machine, laying the groundwork for an upcoming `uc machine logs` command ([#282](https://github.com/psviderski/uncloud/pull/282)). Thanks to @miekg for the contribution ❤️
- Warnings are now printed for detected unsupported Compose features ([#288](https://github.com/psviderski/uncloud/pull/288)). Thanks to @miekg for the contribution ❤️
- New `--auto-confirm` flag for `uc scale` which now always asks for confirmation before changing replica counts
- New `--ulimit` flag for `uc run` to set resource limits
- bumped Go to 1.26.1 and modernized the codebase using Go 1.26 ([#278](https://github.com/psviderski/uncloud/pull/278))
- Migrated TUI components to `lipgloss/v2`, `bubbletea/v2`, and `huh/v2`
## Bug fixes
- Fixed `uc deploy` crash in an initialised but empty git repository ([#275](https://github.com/psviderski/uncloud/pull/275)). Thanks to @tonyo for the contribution ❤️
- Fixed `ucind` downloading the wrong Corrosion architecture on arm64 ([#285](https://github.com/psviderski/uncloud/pull/285)). Thanks to @miekg for the contribution ❤️
- Fixed output contamination in the SSH CLI executor by separating stdout and stderr ([#270](https://github.com/psviderski/uncloud/issues/270))
- Fixed trying other machine connections when the first one fails for the new default `ssh` type. Fixed the TUI progress spinner.
## Upgrade to 0.18.0
### Uncloud CLI locally
To upgrade the Uncloud CLI (`uc`) locally:
```bash
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh
```
### Machine daemon
To upgrade the Uncloud daemon on your machines, run the following commands on each machine:
```bash
# AMD64
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.18.0/uncloudd_linux_amd64.tar.gz
# ARM64
# curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.18.0/uncloudd_linux_arm64.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloud
```
## Changelog
* cb77d42107aa4583a5259a719bef5334b4d1cc29 Merge branch 'docs/uncloud-config'
* b3b33a82baa17a1603a95ed19c441cbafe0a7ff0 chore(e2e): increase ucind cluster init timeouts, decrease max backoff delay for TCP connection to retry faster
* 07e380b95f8455a9a8ec3bf5d5c05fa9a1a5e71b chore(pre-deploy): warn about depends_on: service_completed_successfully to use pre-deploy hook instead
* be0f833e2187bb3b31f4070bf0305170a3ab2bdd chore: add dev:install and dev:reset mise commands to manually test daemon changes on dev machines
* 2992bad05dfc75cb986491b0fef63ef572bc7012 chore: bump Go to 1.26.1 and golangci-lint to 2.11.2 on github actions
* cf3234aef9af9cfed2dadafb773507292ef569b2 chore: bump Go version to 1.26.1
* 6cc3a05ed292d32a6a7496aea8e9f55ee8e57722 chore: bump mise to 2026.3.7 on github actions
* 9fb20c30b33cc557bd0d9c3d557c9d58ae2ba968 chore: extend Uncloud-in-Docker section in HACKING.md
* 29a682f1ce13c7e03bf3563017674739019682fe chore: generate mise.lock for all platforms
* 9e39f03f75ee4ac5f77b7834142a52e54b9c69fd chore: lint
* 255448a59c031024dad24a0f88797a92c1831fdc chore: migrate to hub/v2 and bubbletea/v2
* 33fcb2fe7463094670f253f3acccaf07b7beffaa chore: migrate to lipgloss/v2
* a0dbe4a983f3c37dd22b26c45ea2c1265ec63117 chore: mise ucind:cleanup task to remove ucind managed containers and networks
* 2ab58d24d41539ffe1fd77e266170f62b7e05a37 chore: modernize the codebase using go 1.26 (#278)
* 76880d901aaaffc9d2937690aa84ad354845fcc3 chore: move proto generation to mise tasks
* 18ea1bc4a6a3806d1348c0edd2f09ca805d50d24 chore: remove obsolete Makefile targets
* 7eaf42444d366d8c370bb94ebe45d9407a10a21c ci: update mise action to v4, ignore changes to mise.lock
* 12c82bdb05f4f65a9d050e089208418fb29e75b8 ci: update the lint workflow to run linter instead of formatter
* 117c2abd238118087c175b6b93820f4619d8b260 ci: use latest version of mise action for go-tests
* cef047221c4f103f2997837e2209a317c389319f feat(machine-logs): add server side of journal logs (#282)
* f4581eac1167979e9297d749cb8ac8aa56a1cecc feat(pre-deploy): add pre-deploy hook to service spec
* 1c8b77054a22fcb076879b33891dceb6c427222b feat(pre-deploy): add support for pre-deploy hook containers in service management, sync *all* containers to store
* 0e820f9c52b2aa0214edc9f9629a87a3496cc2e0 feat(pre-deploy): add support for x-pre_deploy extension in Compose + e2e test
* 0da9df17a40a3f9671be8bdc4e2ef499f8c8063a feat(pre-deploy): correct progress events for pre-deploy hooks, make other container events more aligned with plan
* 772b31b57f1249c139a71d6497c56c3a513b3ccb feat(pre-deploy): implement pre-deploy hook operations for deployment
* 043b85ab704b007e2cb3052b6af898d67599f6a9 feat(pre-deploy): include timeout information in pre-deploy hook formatting in plan
* 1930bb576611c757885d37b04908ca468ae38c71 feat(pre-deploy): list hook containers in 'uc ps' and 'uc inspect'
* 7ec8879af38045eb7565b7084290c8bed5ecc793 feat: accept optional -- in uc exec (#301)
* 7f92a5db27d5d10f1bd7a04e4679af5ca393f08e feat: add --ulimit flag for 'uc run' command
* f5a77b82b2a27ee74a662a6e364a02a7c4b86e15 feat: add auto-confirm option for 'uc scale' command, always require confirmation, format scaling plan
* 897f30fd36e3166b89ab9d09ced81503f7e9894e feat: add client/server version check mechanism to gRPC calls (#260)
* 1525d182b516b876510d6e4413ca2fe9ff029b53 feat: add cluster context support in Compose with x-context extension
* 8ae38cfd57d02f42631e0c2bb54c4331b9c072c9 feat: add shm_size support in Compose and --shm-size flag for 'uc run' (closes #267)
* 06c2bc55f2fbf20920613aac45c07952107160a0 feat: make connection method using system 'ssh' the default (add ssh+go:// fallback)
* d38312fec67c8de7d9ca4fdf8cd7ec4db59d0315 feat: print warning on some unsupported compose features (#288)
* 98439b774341030f7a7d1ee37ae3b5c81fd5ee8c feat: support PID namespace mode in Compose (#276)
* eff1bc88d89d2e5f1b82c8a96a70161c9753cec5 feat: uc docs --manual flag to generate manual pages (#302)
* e96cce88c14d5c0ca1fba7b5ccc29f1b6192d228 fix(pre-deploy): exclude hook containers from caddy and dns controllers
* a844cc6f67f31c754ac25133a058a356a8b7f4fe fix(pre-deploy): include hook containers in logs, ls, stop commands
* 3e30a59d4c165901a0e5f7b1bda4840bd4cb4750 fix(pre-deploy): progress event for stopping running hooks
* 442f1d97a12a5d86a434c125519ffd888ca5155e fix: `uc deploy` should not crash in empty git repository (#275)
* a1bde30b578252b2fcc057f73990bef899a7a00c fix: disable interactive prompts for ssh connections to not interfere with TUI
* ba732598870b61c098d3292e3d1bb4083bcb2204 fix: get the correct corrosion version in ucind image (#285)
* 3f95583dd4f95b299d029ec63959102bb9527d1f fix: plan formatting for service scaling (update verb), fix image and replicas diff
* ab644f6a47b13be0157ced035b51c55c33c334b3 fix: race on warned flag in versioncheck pkg, make consistent use of client/server terms
* d2703cbc6b898119017c45b93dbd00071f9b30a2 fix: remove extra line between services in deploy plan
* 9e4c759ffc97757dd38eddbea8f9d8e003ac1222 fix: separate stdout and stderr in SSH CLI executor to prevent output contamination (closes #270)
* cd149e45060bc69f346aece7745f054c985280fd fix: spec validation when name is empty, race in e2e tests
* 940732e91c9ce110ba331dcc379b28aedb157ef7 fix: sshcli unit test and lint
* 9aee75ba283a5212af80ff21bbdce7aae29855bc fix: tests
* 0a9a1db815de284a9970bbf6b4114f0c3d61d4e7 fix: try other connections when ssh+cli connection fails, enable spinner for ssh+cli
* 37c937a57091bc112f634ed441e7775695966d3a lint
* 86251a9354e77f7dbbf0fed0a108d114e4a3e848 lint
* 883f184e375dbdf8b494c6cf641320d94499297b lint
* 1735ef9521a4538eb8b358d944f25ed2f0281ec5 refactor: GetContextOverrideOrCurrent to check if config used
* e22cdf0b18b727d3f9e5c364ee6fda632b073243 refactor: NewTable for consistent CLI table rendering, style images for ls,ps
* fe813302b75bbe60c21a2036378c87791015756b refactor: event ID generation for images, machines, and volumes to align with plan formatting
* 0f4c2110020097d6cf0ecb44981a19e1ff9453cd refactor: format compose deployment plan with style, display target context
* b4b1232375cf0edd8b56b0026cf1d83b4668eee5 refactor: format deployment plan for caddy (uc caddy deploy)
* 4b34c42b76d9a1c47256ac11b647292b43c5a61e refactor: modernize, remove AsPtr (#300)
* 15037f382a4e728d96c24eea245ca72384d38515 refactor: more descriptive error for using --connect with 'uc machine init'
* 30bcb021d2d0fe8238dae2ed1e918dbf875046e7 refactor: move StopGracePeriod from ServiceSpec to ContainerSpec
* 62976f3338ed47723309507f4495575710aaed7e refactor: print warnings for all detected unsupported Compose features, not only first one
* ada9bec2d4c345fe6a4ac6d7f08082f6027e0219 refactor: remove docker dependency for Pid container property
* 21c65b9dbe9e3e24c818120f35fb934509139513 refactor: remove irrelevant property from pid unit test
* 636307d3eadacb9ab3f5fc560a0c164448966fc2 refactor: replace tabwriter with a Table for consistent table rendering across commands
* e4cb71b878d4c01e564e6495e75aaf44a7b4bfed refactor: simplify and speed up plan output formatting by removing name resolver dependency
* 943fea0515e91ae76cbb931b4ed7da9dd0c9411a refactor: simplify journal logs following, fix corrosion unit name
* 68661e57c379213f0bbceefb1e58bc94b2f4fa68 refactor: tui package for CLI styles and prompts, restyle confirmation
* 838839a7e53ba13ab20ff68e982d6ec8c43ac5eb refactor: update deployment plan structure to use typed volume and service operations