Skip to main content



  • You have identified the installation method for the host system:

    • For bare-metal, you have two executables installed on the host operation system path: stellar-horizon and stellar-core.
    • For running Horizon image with Docker daemon, you will use the stellar/stellar-horizon hosted on Docker Hub. You have already pulled the stellar/stellar-horizon image via docker pull stellar/stellar-horizon:<tag_version> onto host. This image contains the stellar-horizon and stellar-core within.
    • For Kubernetes with Horizon Helm Chart, you have followed the Install Horizon with Helm Chart.
  • Initialize database

You are now ready to identify the configuration parameters needed to perform three important roles:

  • Serving read-only API requests via a regular web-based HTTP API;
  • Ingesting ledgers from Core nodes of the Stellar network to keep its world-view up to date;
  • Submitting transactions via a regular web-based HTTP API, forwarding the transaction submission request to the Stellar network.

To perform these roles, you can choose from one of two deployment modes below (single instance deployment or multiple instance deployment). Each has its own configuration parameters.

Single Instance Deployment

Run stellar-horizon in a single o/s process and it will perform all three roles simultaneously.

environment variableexample

Multiple Instance Deployment

In this scalable deployment variant, you run multiple instances of stellar-horizon, each performing a subset of the roles. This allows you to horizontally scale each of the role functions independently.

Ingestion Role Instance

You must allocate at least one instance to perform ongoing ingestion to capture network activity. This will default to limiting storage of ingested network activity in the database to our recommendation of a sliding window of the last 30 days.

environment variableexample

API Role Instance

You can run none or multiple instances to serve read-only API requests. Notice there is no need to define network settings here, as Horizon only reads from database.

environment variableexample

Transaction Submission Role Instance

You can run none or multiple instances to serve transaction submission requests. If you run an instance with transaction submission enabled, the Horizon deployment is required to have at least one instance perform the ingestion role on the same database. Horizon transaction submission depends on this live ingestion taking place against the database in order to confirm tx submission status.

If ingestion is planned to be done on a separate instance, add INGEST=false on this instance, otherwise don't include the parameter, Horizon will default to INGEST=true. When a transaction submission enabled instance has INGEST=true effective, it will configure the related STELLAR_CORE_URL parameter automatically to use the internally launched captive core instance and the deployment does not need to set the configuration value explicitly.

If setting INGEST=false, then must define the STELLAR_CORE_URL variable on this transaction submission enabled instance, since there will be no internally hosted captive core instance as part of ingestion available to reference, instead the STELLAR_CORE_URL provides the ability to define the URL of a core instance HTTP port which Horizon will send transaction submissions towards.

environment variableexample



If you have configured your deployment to perform the ingestion role, then it is strongly recommended to review Ingestion first and Filtering second and factor that into configuration parameters to achieve best performance related to your application requirements before proceeding further.

  • Horizon will create a sub-directory under the current working directory of the o/s process to store captive core runtime data files. Refer to Prerequisites for the type and amount of storage recommended. You can override this location with the optional CAPTIVE_CORE_STORAGE_PATH environment variable, set to a directory on the file system where captive core will store the runtime files.


This config parameter is optional, set as FALSE by default. Controls whether Horizon will accept HTTP requests to the /tx API endpoint and forward to the network. Refer to Channel Accounts for some recommendations on optional client transaction submission optimizations.

  • When set to FALSE, it requires live ingestion process to be running on the same database because Horizon depends on new ledgers from the network to confirm a transaction submission status, Horizon will report a startup error if it detects no live ingestion. Requires INGEST=true or STELLAR_CORE_URL to be defined for access to a Core instance.
  • When transaction submission is disabled by setting it to TRUE, Horizon will return 405 on POSTs to /tx.


This config parameter is optional, can be one of Stellar's public networks, 'pubnet', or 'testnet'. Triggers Horizon to automatically set configurations for remaining Horizon settings and generate the correct core toml/cfg settings. If you only need Horizon to connect to one of those public Stellar networks, this will take care of all related configurations.

  • If you want to connect Horizon to a different Stellar network other than pubnet or testnet or override any of the defaults that NETWORK usage will initiate, the key environment variables that can be set are: HISTORY_ARCHIVE_URLS, CAPTIVE_CORE_CONFIG_PATH, NETWORK_PASSPHRASE, CAPTIVE_CORE_STORAGE_PATH, STELLAR_CORE_URL.


This config parameter is required, specifies the Horizon database. It's value follows this format: dbname=<pg_dbname> user=<pg_user_name> password=<pg_user_pwd> host=<host_address>


This config parameter is optional, can be one of 'info', 'error', 'debug'.


This config parameter is optional, it determines the maximum sliding window of historical network data to retain on the database from ingestion. The value is expressed as absolute ledger count, which is an indirect way to define a duration of time, each ledger being approximately 5 seconds. It is defaulted to 0, which means it will not purge any history from the database. To enact the recommended sliding window of one month, set this to 518400, which is the approximate number of ledgers in 30 days. Refer to Compute Resources for how database storage space is closely related to this setting.

Passing Configurations to Horizon

The stellar-horizon binary searches process environment variables for configuration. Depending on how Horizon was installed, the method you perform to configure the process environment will differ:

  • Bare-metal
    • Non-package manager: use O/S environment variables to pass configurations. There are many tools you can use to manage them, such as direnv or dotenv.
    • Package manager: the provided stellar-horizon-cmd wrapper will start a new process and create environment variables in the process from /etc/default/stellar-horizon and then launch the 'stellar-horizon'. To set configurations, edit the file at /etc/default/stellar-horizon.

      This script invokes Horizon with the stellar user, so make sure that permissions for the user are set up accordingly. The current working directory should be writable for this user and the user should be able to execute the stellar-horizon and stellar-core binaries; etc.

  • Containerized

Initialize Horizon Database

Before running the Horizon server for the first time, you must initialize the Horizon database. This database will be used for all of the information produced by Horizon, most notably historical information about transactions that have occurred on the Stellar network.

To prepare a database for Horizon's use, first ensure it is blank. It's easiest to create a new database on your PostgreSQL server specifically for Horizon's use. We recommend creating a new user(role) in postgres dedicated to Horizon's database and assigning that user(role) as the owner of this database.

To illustrate an example using psql, first login to the database server using the psql command-line tool as a superuser, and then create the new user(role) and database for Horizon:

postgres=# CREATE ROLE horizon WITH LOGIN;
postgres=# CREATE DATABASE horizon OWNER horizon;

Additionally, you can set a password on your new horizon postgres user with ALTER USER.

Once completed, you can compose the full value of the configuration parameter for db access DATABASE_URL="dbname=horizon user=horizon password=<value_here> host=<address_of_pg_server>".

Next, execute the Horizon binary to install the schema onto the empty db from the command line. In this example, assume the current shell doesn't have DATABASE_URL in environment yet, so export it first into shell:

$ export DATABASE_URL="dbname=horizon user=horizon password=<value_here> host=<address_of_pg_server>"
$ stellar-horizon db init

Optional Postgres Configurations

Based on performance observations over time, we recommend additional Postgres configuration settings(postgresql.conf), but these are not required:

  • Set random_page_cost=1 if you are using SSD storage. With this setting, Query Planner will make a better use of indices, especially for JOIN queries. We've noticed a huge speed improvement for some queries with this setting.

_ To improve availability of ingestion, api, transaction submission servers it's recommended to set the following values:

  • tcp_keepalives_idle: 10 seconds
  • tcp_keepalives_interval: 1 second
  • tcp_keepalives_count: 5

With the config above, if there are no queries from a given client for 10 seconds, Postgres should start sending TCP keepalive packets. It will retry 5 times every second. If there is no response from the client after that time it will drop the connection.

Next Step

After configuration is complete, you are now ready to proceed to Running Horizon!