# write_file

Source: https://modulify.ai/docs/api/code/write-file

Writes one or more source files straight into the running preview of a site, replacing whatever was at each path.

- Title: Write files to a site
- Scope: `code:write`
- Access: Destructive
- Endpoint: `POST /v1/write_file`

It takes up to 20 files per call. Each one replaces the whole file rather than patching it, so read the file first with `read_file`, and a path that does not exist yet is created.

The preview has to be running: with nothing to write to, the call is refused rather than queued, so open the preview first. Each file is confirmed individually by the preview, and the response lists the paths that were written in `written` and the ones that failed, with the reason, in `failed`, so read that rather than assuming a success means everything landed.

It is also refused, with the same message `send_message` and `publish_site` give, while the site code is being moved into GitHub or back to Modulify, when Modulify has lost access to the GitHub repository that holds the site or that repository was archived or deleted, and when the code lives in the workspace's own GitHub but the workspace is on the Free plan. See [Move your code to GitHub](https://modulify.ai/docs/editor/move-code-to-github).

This does not go through the site AI, so nothing about the change is explained or reviewed, and **no code backup is taken when it is written**. It only reaches the code backup history, as a **Preview sync** entry, once the preview is next saved: when the editor opens, just before a publish, or after a chat run is stopped or fails.

Take a backup with `create_backup` first for anything beyond a small edit. Use `send_message` instead when someone described what they want rather than exactly what to write, because the AI reads the surrounding code and this does not. See [Backups](https://modulify.ai/docs/editor/backups).

## Request

Call it with a `POST` to `https://api.modulify.ai/v1/write_file`, sending the inputs below as a JSON object. The token needs the `code:write` scope.

> **Warning**
>
> This method is marked destructive: it deletes or overwrites data. Check the inputs before you call it, and send an [Idempotency-Key](https://modulify.ai/docs/api/idempotency) header whenever you might retry it.

```bash
curl -X POST https://api.modulify.ai/v1/write_file \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"PROJECT_ID","files":[]}'
```

Over MCP, the same method is the [write_file tool](https://modulify.ai/docs/mcp/code/write-file).

## Inputs

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string | Yes | The site id. |
| `files` | array of objects | Yes | The files to write, at most 20 per call. Each object has `Path`, such as `app/page.tsx`, `Content` with the complete new contents, and an optional `Encoding`, `utf8` by default or `base64` for a binary file. A leading slash in `Path` is stripped, and a path stepping outside the site is refused. |

## Response

Every call answers with the [JSON envelope](https://modulify.ai/docs/api/requests-and-responses#the-response) of `success`, `message`, `data`, `code` and `version`. `data` holds the result described above, and on a method that returns a total, `count` carries it. The [response headers](https://modulify.ai/docs/api/requests-and-responses#headers-on-every-method-call) carry the call's `X-Request-Id` and what is left of your per-minute budget in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. [Errors](https://modulify.ai/docs/api/errors) explains every status code a call can answer with.