1---
2title: Volumes
3description: Durable network block storage for Hetzner Servers — attach with props or VolumeAttachment, mount into Services with the MountVolume binding.
4---
5
6A [`Volume`](/providers/hetzner/volume) is Hetzner's network block
7storage: a durable disk (10 GB minimum) with its own lifecycle,
8attachable to one Server at a time in the same location. Servers
9come and go; Volumes keep the data.
10
11## Create a Volume
12
13```typescript
14import * as Hetzner from "alchemy/Hetzner";
15
16export const Data = Hetzner.Volume("data", {
17 size: 10,
18 format: "ext4",
19 location: "nbg1",
20});
21```
22
23`size` is in GB and can **grow in place** on a later deploy —
24shrinking is impossible. `format` (`ext4` or `xfs`) and `location`
25are create-only: changing either **replaces the Volume and destroys
26its data**. The location must match the Server's.
27
28## Mount into a Service (recommended)
29
30The `MountVolume` binding is the highest-level path: inside a
31[Service](/hetzner/compute/services)'s constructor, bind the Volume to a
32path and use it as a plain directory at runtime. Pass the `Data`
33declaration directly — no yielding required:
34
35```typescript
36export default class Api extends Hetzner.Service<Api>()(
37 "Api",
38 { server: Box, main: import.meta.url, port: 3000 },
39 Effect.gen(function* () {
40 const mount = yield* Hetzner.MountVolume(Data, { path: "/data" });
41
42 return {
43 fetch: Effect.gen(function* () {
44 const fs = yield* FileSystem.FileSystem;
45 const text = yield* fs.readFileString(`${mount.path}/hello.txt`);
46 // ...
47 }),
48 };
49 }).pipe(Effect.provide(Hetzner.MountVolumeLive)),
50) {}
51```
52
53At deploy time the binding attaches the Volume to the Service's
54Server, creates the directory, mounts the device, and appends an
55`/etc/fstab` entry (`defaults,nofail`) so the mount survives
56reboots. At runtime it hands you the resolved `mount.path` and
57`mount.device`. Every step is idempotent, and two Services binding
58the same `(volume, path)` on the same Server share one attach and
59one mount.
60
61If the Server is ever replaced, the Volume is detached from the old
62machine and re-attached to the new one on the next deploy — the
63data rides along.
64
65## Attach without a Service
66
67For servers that manage their own filesystems, attach declaratively
68instead. Either from the Volume side:
69
70```typescript
71export const Data = Hetzner.Volume("data", {
72 size: 10,
73 location: "nbg1",
74 server: Box,
75 automount: true,
76});
77```
78
79Or as a standalone
80[`VolumeAttachment`](/providers/hetzner/volumeattachment) — useful
81when the Volume and Server are declared far apart:
82
83```typescript
84yield* Hetzner.VolumeAttachment("data-on-box", {
85 volume: Data,
86 server: Box,
87 automount: true,
88});
89```
90
91With `automount: true` Hetzner mounts the disk under
92`/mnt/HC_Volume_<id>`; otherwise mount `volume.linuxDevice`
93yourself (e.g. via cloud-init or `Hetzner.Ssh`).
94
95## Where next
96
97- [Tutorial part 3](/hetzner/tutorial/part-3) — mount a Volume into
98 a Service step by step.
99- [Services](/hetzner/compute/services) — the platform doing the
100 mounting.
101- [`Volume` reference](/providers/hetzner/volume) — every prop and
102 attribute.