# Hot deployment

Deploying services by saving a file in your project without server restarts.

Hot deployment means that saving a Python file in your project deploys it to a running Zato environment within a couple of seconds, with no restarts and no manual steps. The same mechanism also deploys configuration files, rule files and enmasse definitions.

Your services live in a project directory on your host or in your git repository, the directory is mounted into the Zato container, and the platform watches it for changes. You never copy files into the container and you never edit anything inside it - the project on the host is the single source of truth, as described in the [deployment tutorial](https://zato.io/tutorials/devops/deployment.html).

## A complete scenario {#a-complete-scenario}

Everything below runs as is - a new project, one service and the container that deploys it.

Create the project directory on your host:

```bash
mkdir -p ~/myproject/impl/src/api
```

Save this as `~/myproject/impl/src/api/hello.py`:

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

# ##############################################################################

class HelloService(Service):
    """ Replies with a greeting.
    """
    name = 'api.hello'

    def handle(self):
        self.logger.info(f'cid:{self.cid} Received a new request')
        self.response.payload.message = 'Hello from a hot-deployed service'

# ##############################################################################
```

Start a container with the project mounted and pointed at through `Zato_Project_Root`:

```bash
docker run --pull=always -it --rm -p 22022:22 -p 8183:8183 -p 11223:11223 \
  --name zato-4.1 -e Zato_Password=mypassword \
  -e Zato_Project_Root=/opt/hot-deploy/myproject \
  -v ~/myproject:/opt/hot-deploy/myproject:ro \
  zatosource/zato-4.1
```

Once the environment is up, the server log confirms the deployment:

```text
Deployed 1 service from `hello.py` -> ['api.hello']
```

Invoke the service from the Dashboard at [http://localhost:8183](http://localhost:8183) under **Services** -> **IDE** - select `api.hello`, click **Invoke** and the response is:

```json
{"message": "Hello from a hot-deployed service"}
```

Now change the greeting in `hello.py` on your host and save the file. A moment later the log reports the same deployment line again - invoke the service once more and the new text is in the response. That is the whole workflow: save, wait a second, invoke.

The rest of this page is the reference behind the scenario - the layout rules, the deployment order and what else is watched besides Python files.

## From your IDE {#from-your-ide}

Because the project directory is mounted into the container, any editor that saves a file into it triggers the deployment - VS Code, PyCharm, Cursor or Vim, with no plugin and nothing to configure in the editor. Open the project, save, and the server picks it up. When the server runs on a remote machine and there is no directory to mount, the [VS Code plugin](https://zato.io/docs/dev/ide/vscode.html) does the same over HTTP - the [IDE page](https://zato.io/docs/dev/ide/index.html) covers both ways.

## The project layout {#the-project-layout}

A project follows the layout of the [project blueprint](https://github.com/zatosource/zato-project-blueprint):

```text
myproject
├── config
│   ├── enmasse
│   │   └── enmasse.yaml
│   ├── python-reqs
│   │   └── requirements.txt
│   └── user-conf
│       └── myproject.ini
├── impl
│   ├── scripts
│   │   ├── run-container.sh
│   │   └── run-tests.sh
│   └── src
│       └── api
│           └── crm.py
└── testing
    └── tests
        ├── test_billing.py
        └── test_crm.py
```

Two rules make a directory deployable:

- Code must be under a directory named `src`
- Directories under `src` must start with one of these prefixes: `api`, `common`, `util`, `model`, `core`, `channel`, `adapter`, `services`

Nested directories are allowed and nested packages need an `__init__.py` file.

## How the platform finds your project {#how-the-platform-finds-your-project}

The `Zato_Project_Root` environment variable points to the project directory. With the blueprint, the provisioning script writes it to `config/auto-generated/env.ini` and the container reads it from there - you do not set it by hand.

More than one project can be deployed at a time - each additional one uses its own variable with any suffix, e.g. `Zato_Project_Root_Billing`, and all of them accept multiple colon-separated paths.

## Deployment order {#deployment-order}

Directories deploy in a fixed order of their prefixes:

```text
common → util → model → core → channel → adapter → api → services
```

Shared code deploys first, which is why modules with models and utilities belong under `common`, `util` or `model`, while the services that use them belong under `api` or `services`.

## Pickup patterns {#pickup-patterns}

The `Zato_Hot_Deploy_Pickup_Patterns` environment variable adds directories with other names. Its value is a comma-separated list of glob patterns, matched under each `src` directory, and the directories they match deploy after those of the default prefixes, in the order of the list:

```text
Zato_Hot_Deploy_Pickup_Patterns=integrations*/**,jobs*/**
```

## Imports between deployed files {#imports-between-deployed-files}

The `src` directory of each project becomes an import root. A module imports another one by its path relative to `src`:

```python
# In impl/src/api/billing.py, importing from impl/src/common/models.py
from common.models import Customer
```

When a shared module changes, every service that imports it is redeployed automatically - saving `common/models.py` also redeploys `api/billing.py` if it imports from that module.

## What is watched and when it deploys {#what-is-watched-and-when-it-deploys}

The platform watches the project recursively, subdirectories included, for these file types:

- `*.py` - services and shared modules
- `*.ini` - [configuration files](https://zato.io/docs/dev/examples/config.html), reloaded in RAM with no restart
- `*.zrules` - [rule engine](https://zato.io/docs/rule-engine/tutorial.html) rules
- `enmasse*.yaml` and `enmasse*.yml` - [enmasse definitions](https://zato.io/docs/admin/enmasse.html), imported on change

A file deploys after it has been saved and its size has settled, which in practice means a second or two after you save it in your editor. Compiled artifacts and directories such as `__pycache__` or `.git` are ignored.

## Deploying from the Dashboard {#deploying-from-the-dashboard}

The Dashboard offers two ways to deploy a service without touching the file system:

- The service list has an upload area where a `.py` file can be dropped
- The built-in IDE edits and deploys services directly in the browser

Both are convenient for experimentation, but anything created this way exists only inside the container and disappears when the container stops. Work that needs to survive belongs in the project directory in git - the [deployment tutorial](https://zato.io/tutorials/devops/deployment.html) covers the workflow.

## Learn more {#learn-more}

- [Development documentation](https://zato.io/docs/dev/) - The complete reference for writing services
- [Requests and responses](https://zato.io/docs/dev/request-response/) - What a service receives, what it returns and how both are structured
- [Integration examples](https://zato.io/docs/dev/examples/) - Ready-made code for the systems you are likely to connect to
- [IDE and debugging](https://zato.io/docs/dev/ide/) - Write services in the Dashboard or in your own editor
- [Data models](https://zato.io/docs/dev/model/) - Declare inputs and outputs and have them validated for you
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - The full platform tutorial, from installation to production patterns
