Installing To Italy: A Practical Walkthrough

To Italy is a regional logistics and routing optimization tool that handles shipment tracking, customs documentation, and carrier integration specifically for Italian market operations. Getting it set up correctly matters because the configuration touches shipping workflows, and a misconfigured instance will silently drop data or send packages through the wrong routing tier. I run this in production across three warehouses. The standard install path goes through npm or a direct binary download, depending on your environment. Most teams hit issues around environment variables, not the core installation itself. Here is the breakdown. You need Node.js version 18 or higher. I have seen attempts with Node 16 fail at the dependency resolution stage, so do not bother. Docker support is available but optional. A PostgreSQL 14+ instance is required for the production mode. Redis 6+ is needed if you are enabling the async queue processor. You will also need API credentials from at least one major Italian carrier — BRT, SDA, or FedEx Italia — before the installer finishes, because it validates endpoint connectivity during setup.

The install command is straightforward: npm install -g to-italy Or if you are pulling the binary:

wget https://releases.toitaly.io/v3.2.1/to-italy-linux-amd64 -O /usr/local/bin/to-italy && chmod +x /usr/local/bin/to-italy After that, run the initialization wizard: to-italy init

Get the Full Details

Italy in Summer - The Monastery Stays Blog
Italy in Summer - The Monastery Stays Blog

This creates the configuration directory at ~/.to-italy/ and generates the config.yaml file. The wizard prompts for your database connection string, carrier API keys, and the default warehouse region code. Set the region code to the correct province — MI for Milan, RM for Rome, NA for Naples. This is not cosmetic. The routing engine uses this to determine which carrier has the best SLA for that zone.

Database Setup

Create the database before running migrations: psql -U postgres -c "CREATE DATABASE to_italy_production;" Then run the migration:

to-italy db:migrate The migration process takes roughly 30 seconds on a clean database. If it hangs past two minutes, check your connection string for special characters in the password. URL encoding issues cause the migration to stall without throwing an error, which I learned the hard way during a Friday deploy.

Sorrento Italy Free Stock Photo - Public Domain Pictures
Sorrento Italy Free Stock Photo - Public Domain Pictures

Carrier Configuration

Carrier integrations go into the config file under the carriers section. Here is a working example for BRT: ```yaml carriers: bdt: enabled: true api_key: "${BRT_API_KEY}" environment: sandbox default_service: express_12 webhook_url: "https://api.yourdomain.com/webhooks/brt" sda: enabled: true api_key: "${SDA_API_KEY}" environment: production default_service: standard webhook_url: "https://api.yourdomain.com/webhooks/sda" ``` Keep environment set to sandbox until you have validated your shipment creation flow end-to-end. Switching to production too early burned us once with actual shipments being created in test mode, which means tracking numbers were assigned but not visible to customers.

Starting the Service

Run it with: to-italy start --env production The service binds to port 3000 by default. Health checks are available at /health. If the endpoint returns a 200 with {"status": "ok"}, the core routing engine and database connection are functional. The carrier connectivity check runs separately and shows at /health/carriers.

Common Pitfalls

One issue that catches everyone: timezone handling. To Italy runs queries against local Italian time (CET/CEST), but if your server is set to UTC and you do not configure the timezone override in the config, address validation for Italian municipalities can return stale results. Set timezone: Europe/Rome in your config and restart. This fixed a recurring bug where packages to Sicily were being routed through the mainland depot overnight instead of the Palermo hub. Another thing: the rate limiter. By default, the sandbox environment enforces a strict rate limit of 10 requests per second. If you are bulk-generating shipping labels, you will hit this within minutes. Increase it in production mode, but do not exceed 50 req/s without contacting your carrier account manager. BRT throttles at 100 req/s on their side, and exceeding that gets your API key suspended.

Atrani – an Undiscovered Town on the Amalfi Coast, Italy
Atrani – an Undiscovered Town on the Amalfi Coast, Italy

Testing Your Setup

Use the built-in test command after installation: to-italy test:connectivity This pings all configured carriers and validates the database schema. A clean output looks like this:

Database: connected (PostgreSQL 15.4) BRT: sandbox OK (latency: 142ms) SDA: production OK (latency: 89ms)

Route optimizer: 3 zones loaded If any line shows a failure, the output includes a short diagnostic code. The BRT sandbox error typically means your API key format is wrong — they switched from alphanumeric to a 64-character hex format in 2024, and old keys from documentation examples will fail.

Italy Travel Poster Free Stock Photo - Public Domain Pictures
Italy Travel Poster Free Stock Photo - Public Domain Pictures

Production Deployment Notes

Running behind a reverse proxy is standard. I use Nginx with SSL termination. The service itself does not handle HTTPS natively, so do not attempt to run it exposed without a proxy in front. WebSocket support is available for real-time tracking updates on port 3001, but it requires the same SSL setup. Memory usage sits at about 250MB idle and scales to roughly 800MB under active label generation with five carriers configured. If you see it climb past 1.2GB, check for connection leaks in your carrier webhook handlers. We had one handler that did not close the response stream properly, causing a slow memory drain over 12 hours. Backups of the database should happen at least daily. The schema is relatively lightweight — roughly 2GB after three months of transactional data. Point-in-time recovery is available if you use WAL archiving with your PostgreSQL setup, and I would recommend enabling it since a corrupted migration during an update can wipe the routing table if you do not have a snapshot.

The official documentation lives at docs.toitaly.io, but it lags behind the current release by about two releases. The changelog in the GitHub repository has more accurate information about breaking changes between versions. Stick to major version updates for production — minor patch releases are generally safe, but a jump from v3 to v4 required a schema migration that is not backward compatible.