How to Run Your Own Polygon PoS Node

A Polygon PoS node is two daemons, not one: Bor (the execution layer, a Geth fork that serves your eth_* RPC on chain ID 137) and Heimdall(the consensus/validation layer, built on CometBFT and the Cosmos SDK). Each one consumes the other’s API, they must be started in a strict order, and they upgrade in coordinated pairs. This guide is the official 2026 setup for a mainnet full node (sentry type) on Ubuntu.

Before you copy-paste an older tutorial: mainnet migrated from Heimdall v1 to Heimdall v2 on July 10, 2025. The old heimdall repo is archived, v1 snapshots and guides no longer work, and fresh installs need the v2 migrated genesis. Anything written before that date will not bring up a working node.

Hardware requirements

ResourceMinimum (docs)RecommendedReality check
CPU8 cores16 cores
RAM32 GB64 GB
Disk4 TB6 TBThe docs’ 4 TB is already stale-low: current community full snapshots for Bor run ~5.8 TB extracted. Buy 8 TB NVMe or plan a migration within the year.
Network1 Gbit/s1 Gbit/sThe snapshot download alone is a day-scale job.

This is a full node. A Polygon archive node is a different animal entirely (Erigon-based, 16 TB+, RAID-0 IOPS requirements) — most people don’t need it.

Step 1: install both clients

There’s no apt repository; the official path is .deb packages driven by install scripts from 0xPolygon/install. As of this writing the current pair is Bor v2.10.0 and Heimdall v2 v0.11.0(check both release pages — these move monthly, and skip beta tags). The third argument sentry is the non-validator full-node profile:

sudo apt-get update && sudo apt-get install -y build-essential curl

# Heimdall v2 (consensus)
curl -L https://raw.githubusercontent.com/0xPolygon/install/heimdall-v2/heimdall-v2.sh \
  | bash -s -- v0.11.0 mainnet sentry

# Bor (execution)
curl -L https://raw.githubusercontent.com/0xPolygon/install/main/bor.sh \
  | bash -s -- v2.10.0 mainnet sentry

The packages install systemd units (heimdalld.service, bor.service) and config profiles. Key locations: Bor lives in /var/lib/bor (config.toml, data in data/); Heimdall lives in /var/lib/heimdall/config/ (CometBFT config.toml, Cosmos app.toml, genesis.json). A fresh install needs the v2 migrated mainnet genesis (chain heimdallv2-137) from Polygon’s genesis bucket.

The part that makes Polygon different: the two daemons are cross-wired. Bor’s config points at Heimdall’s REST API ([heimdall] url = "http://localhost:1317") and Heimdall’s app.toml points back at Bor’s RPC (bor_rpc_url = "http://localhost:8545"). Neither is optional; a full node runs both, always.

Step 2: bootstrap from snapshots

The docs are blunt: sync from genesis “takes several days” (in practice, far longer for Bor) — use snapshots. Polygon no longer hosts its own; the docs point to community providers aggregated at all4nodes.io/Polygon(Stakecraft, PublicNode/Allnodes, Stakepool, Vaultstaking). You need two snapshots — one per daemon. Heimdall’s pruned snapshot is tiny (~5 GB); Bor’s is the ~5.8 TB monster. Stream-extract straight into the data directories:

sudo systemctl stop heimdalld bor 2>/dev/null

# heimdall data (small)
wget -O - <heimdall_snapshot_url> | sudo tar -xvf - -C /var/lib/heimdall/data/

# bor chaindata (multi-TB; runs for many hours)
wget -O - <bor_snapshot_url> | sudo tar -xvf - -C /var/lib/bor/data/bor/chaindata/

sudo chown -R heimdall:nogroup /var/lib/heimdall
sudo chown -R bor:nogroup /var/lib/bor

Check each provider’s page for the exact target paths and ownership — layouts differ slightly. PublicNode also offers a PBSS/PebbleDB flavor matching Bor’s newer storage profile.

Step 3: start in the required order

This is the most docs-warned failure mode in the entire setup: Heimdall must be fully synced before Bor starts. Bor derives its view of checkpoints and the validator set from Heimdall’s REST API; start Bor early and you get a node that misbehaves in confusing ways.

sudo systemctl start heimdalld
journalctl -u heimdalld.service -f          # watch it catch up

# wait until catching_up is false:
curl -s localhost:26657/status | jq .result.sync_info.catching_up

sudo systemctl start bor
journalctl -u bor.service -f

Step 4: verify

# Heimdall synced?
curl -s localhost:26657/status | jq .result.sync_info.catching_up   # false

# Bor synced?
curl -s -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_syncing","params":[]}' \
  localhost:8545                                                     # {"result":false}

# right chain?
curl -s -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}' \
  localhost:8545                                                     # 0x89 = 137

Ports: keep 30303 (Bor p2p) and 26656 (Heimdall p2p) open to the world; keep 8545/8546 (RPC), 26657 (CometBFT RPC), and 1317(Heimdall REST) local or firewalled. Once synced, sanity-check your node’s height against an independent endpoint — a node can be alive but stale.

What it really costs to run

  • Two daemons, twice the fragility. Bor depends on Heimdall’s :1317 and Heimdall calls Bor’s :8545. A wedged Heimdall takes your “Ethereum-compatible” RPC down with it, and every restart must respect the sync-order rule.
  • The hard-fork treadmill is fast. Polygon shipped mainnet forks roughly every 4–8 weeks through 2026 (Valencia in July, Austin in August, Kyoto already scheduled). Bor and Heimdall release in coupled pairs — upgrade both, on their deadline, or fork off the network.
  • Disk outruns the docs. Official requirements say 4 TB; the live full snapshot is ~5.8 TB and growing. Storage planning is a recurring job, not a purchase.
  • Snapshot bootstrap is a day-plus project. Multi-TB downloads, stream-extraction, ownership fixes, then hours of catch-up sync — and you’ll do it again after any corruption.
  • One node is a single point of failure. Production wants two of everything plus health checks — see Self-Hosted Node vs RPC Provider for the full cost math.

…or skip all of it

SwiftNodes runs load-balanced Polygonnodes for you — flat-rate pricing, HTTP + WebSocket, archive access on paid plans, no KYC — alongside 75+ other chains under one API key. No Heimdall babysitting, no fork-deadline calendar.

Grab a key at swiftnodes.io and point your app at https://rpc.swiftnodes.io/rpc/polygon?key=YOUR_API_KEY.