Configuring ENSIndexer
ENSIndexer requires private RPC endpoints. Public (rate limited) RPC endpoints will not provide acceptable performance.
You must configure private (paid) RPC services from providers like drpc.org, Alchemy, QuickNode, or Infura or host your own RPC service that can handle high-volume requests.
Warning: Configuring ENSIndexer to use the public ENSRainbow server (https://api.ensrainbow.io
) will significantly slow down indexing.
For optimal indexing performance, always colocate ENSIndexer and ENSRainbow. For example, if you are running ENSIndexer locally, you should also run a local instance of ENSRainbow and set ENSRAINBOW_URL
to your local ENSRainbow server.
ENSIndexer’s behavior can be configured through environment variables. Copy .env.local.example
to .env.local
and configure all required values.
# The port ENSIndexer listens on for HTTP requests.# Optional. If this is not set, the default value is set to `DEFAULT_PORT` (42069).PORT=42069
# RPC configuration# Required. When ENSIndexer starts up it verifies RPCs are defined for each of the chains# that are to be indexed based on the configured NAMESPACE and PLUGINS, along with the ENS Root Chain.## NOTE: You must configure your own private RPC endpoints.# ENSIndexer makes millions of RPC requests during operation.# Public RPC endpoints are rate limited and will not provide acceptable performance.# You must use only private (paid) RPC endpoints or your own self-hosted RPC service# that is prepared to support millions of requests (ex: 500+ requests / second)## Each configured RPC endpoint must be prepared to receive and quickly# process millions of RPC requests. Private RPC service options include:# - drpc.org (paid plan) - https://drpc.org/# - Alchemy (paid plan) - https://www.alchemy.com/# - QuickNode (paid plan) - https://www.quicknode.com/# - Infura (paid plan) - https://infura.io/# - Self-hosted RPC nodes## For the RPC URL of each chain, follow the format: RPC_URL_{chainId}={rpcUrl}## E.g. for Ethereum Mainnet using Alchemy:# RPC_URL_1=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY## For the optional RPC rate limits of each chain, follow the format:# RPC_REQUEST_RATE_LIMIT_{chainId}={rateLimitInRequestsPerSecond}# The rate limit is the maximum number of requests per second that can be made# to the RPC endpoint. For private (paid) RPC endpoints, the rate limit can be# set to higher values, depending on the capacity of the endpoint.# Default: 500 (suitable for private paid RPC services - public endpoints will fail)# If no rate limit is set for a given chainId, the DEFAULT_RPC_RATE_LIMIT (500)# will be applied.## Note: Ponder dynamically adapts to the configured rate limits to avoid 429 errors and# maximize performance. More details at: https://ponder.sh/docs/config/chains#rpc-endpoints
# === ENS Namespace: Mainnet ===# Ethereum Mainnet# - required if the configured namespace is mainnet# - required by plugins: subgraph, reverse-resolvers, referrals, tokenscopeRPC_URL_1=RPC_REQUEST_RATE_LIMIT_1=500
# Optimism Mainnet# - required by plugins: threedns, reverse-resolvers, tokenscopeRPC_URL_10=RPC_REQUEST_RATE_LIMIT_10=500
# Base Mainnet# - required by plugins: basenames, threedns, reverse-resolvers, tokenscopeRPC_URL_8453=RPC_REQUEST_RATE_LIMIT_8453=500
# Arbitrum Mainnet# - required by plugins: reverse-resolversRPC_URL_42161=RPC_REQUEST_RATE_LIMIT_42161=500
# Linea Mainnet# - required by plugins: lineanames, reverse-resolvers, tokenscopeRPC_URL_59144=RPC_REQUEST_RATE_LIMIT_59144=500
# Scroll Mainnet# - required by plugins: reverse-resolversRPC_URL_534352=RPC_REQUEST_RATE_LIMIT_534352=500
# === ENS Namespace: Sepolia ===# Ethereum Sepolia (public testnet)# - required if the configured namespace is sepolia# - required by plugins: subgraph, reverse-resolvers, referrals, tokenscopeRPC_URL_11155111=RPC_REQUEST_RATE_LIMIT_11155111=500
# Base Sepolia (public testnet)# - required by plugins: basenames, reverse-resolvers, tokenscopeRPC_URL_84532=RPC_REQUEST_RATE_LIMIT_84532=500
# Linea Sepolia (public testnet)# - required by plugins: lineanames, reverse-resolvers, tokenscopeRPC_URL_59141=RPC_REQUEST_RATE_LIMIT_59141=500
# Optimism Sepolia (public testnet)# - required by plugins: reverse-resolvers, tokenscopeRPC_URL_11155420=RPC_REQUEST_RATE_LIMIT_11155420=500
# Arbitrum Sepolia (public testnet)# - required by plugins: reverse-resolversRPC_URL_421614=RPC_REQUEST_RATE_LIMIT_421614=500
# Scroll Sepolia (public testnet)# - required by plugins: reverse-resolversRPC_URL_534351=RPC_REQUEST_RATE_LIMIT_534351=500
# === ENS Namespace: Holesky ===# Ethereum Holesky (public testnet)# - required if the configured namespace is holesky# - required by plugins: subgraph, reverse-resolvers, referrals, tokenscopeRPC_URL_17000=RPC_REQUEST_RATE_LIMIT_17000=500
# === ENS Namespace: ens-test-env ===# ens-test-env (local testnet)# - required if the configured namespace is ens-test-envRPC_URL_1337=RPC_REQUEST_RATE_LIMIT_1337=500
# Database configuration# Required. This is a namespace for the tables that the indexer will create to store indexed data.# It should be a string that is unique to the running indexer instance.## Keeping the database schema unique to the indexer instance is important to# 1) speed up indexing after a restart# 2) prevent data corruption from multiple indexer app instances writing state# concurrently to the same db schema## No two indexer instances can use the same database schema at the same time.## Read more about database schema rules here:# https://ponder.sh/docs/api-reference/database#database-schema-rules## Avoid using the `public` schema as we force that in the `dev` command. Using `public`# cause conflicts as you interchange between dev and start commands so use literally# anything else.DATABASE_SCHEMA=production# Required. This is the connection string for the database that the indexer will use to store data.# It should be in the format of `postgresql://<username>:<password>@<host>:<port>/<database>`DATABASE_URL=postgresql://dbuser:abcd1234@localhost:5432/my_database
# ENS Namespace Configuration# Required. Must be an ENS namespace's Identifier such as mainnet, sepolia, holesky,# or ens-test-env. (see `@ensnode/datasources` for available options).NAMESPACE=mainnet
# Plugin Configuration# Required. Identify which indexer plugins to activate (see `src/plugins` for available plugins)# This is a comma separated list of one or more available plugin names (case-sensitive).# NOTE:# - for subgraph-compatible indexing, the only valid configuration is `PLUGINS=subgraph`.# - for protocol acceleration of primary name lookups (reverse resolution), enable the# reverse-resolvers plugin.PLUGINS=subgraph,basenames,lineanames,threedns,reverse-resolvers,referrals,tokenscope
# ENSRainbow service URL# Required. This is the URL of the ENSRainbow server that ENSIndexer will use to heal# unknown labels. The best indexing performance requires a colocated deployments of# ENSIndexer and ENSRainbow services to minimize latency. For example, both services should# communicate over the same local network.# Read more about ENSRainbow here:# https://ensrainbow.io# If you need to temporarily use the public ENSRainbow server for testing, set the following:# ENSRAINBOW_URL=https://api.ensrainbow.io (NOT RECOMMENDED - WILL MAKE INDEXING VERY SLOW!!)ENSRAINBOW_URL=http://localhost:3223
# Pinned Label Set Configuration for requests to ENSRainbow# Required. ENSIndexer must be pinned to a specific label set ID and version to ensure deterministic# indexing results across time.## For a list of available label sets and their configurations, visit:# https://ensnode.io/ensrainbow/usage/available-label-sets/## LABEL_SET_ID: The label set identifier that will be used for label healing requests sent to ENSRainbow.# Each label set id references a collection of rainbow records.# This must match the label set ID configured in your ENSRainbow server.## For full subgraph backwards compatibility, LABEL_SET_ID must be set to "subgraph"# and LABEL_SET_VERSION must be set to 0.LABEL_SET_ID=subgraph
# LABEL_SET_VERSION: A non-negative integer representing the version of the label set to request from ENSRainbow.# This "fully pins" ENSIndexer to a deterministic set of ENSRainbow label healing responses across time,# even if the connected ENSRainbow later ingests additional records into the same label set.# This must be less than or equal to the label set version configured in your ENSRainbow server.## For full subgraph backwards compatibility, LABEL_SET_ID must be set to "subgraph"# and LABEL_SET_VERSION must be set to 0.LABEL_SET_VERSION=0
# The ENSIndexer public service URL for handling external API requests# Required. When the root route `/` of ENSIndexer receives a request, ENSIndexer redirects to# the configured ENSADMIN_URL with an instruction for that ENSAdmin instance to connect back# to this provided URL for querying state about the ENSNode instance.ENSNODE_PUBLIC_URL=http://localhost:42069
# The "primary" ENSIndexer service URL# Required. This must be an instance of ENSIndexer using either `ponder start`# or `ponder dev`, and not `ponder serve`.# This URL is used to read Ponder's internal indexing state using# the `/status` and `/metrics` endpoints that are served directly by Ponder# within the specified ENSIndexer.# For ENSIndexer instances started using `ponder start` or `ponder dev`,# this should be configured so that ENSIndexer refers back to itself, ex:# http://localhost:{port}. For ENSIndexer instances started using# `ponder serve`, this should be set to the hostname of# the related ENSIndexer instance started using `ponder start` or# `ponder dev` that is writing to the same ENSDb.ENSINDEXER_URL=http://localhost:42069
# The ENSAdmin service URL# Optional. When the root route `/` of ENSIndexer receives a request, ENSIndexer redirects# to this provided ENSAdmin URL with an instruction for that ENSAdmin instance to connect# back to the configured ENSNODE_PUBLIC_URL.## If this is not set, DEFAULT_ENSADMIN_URL (https://admin.ensnode.io) will be used# to provide easy access to an ENSAdmin UI.ENSADMIN_URL=https://admin.ensnode.io
# A feature flag to enable or disable healing of addr.reverse subnames# Optional. If this is set to true, ENSIndexer will attempt to heal subnames of addr.reverse# If this is not set, the default value is set to `DEFAULT_HEAL_REVERSE_ADDRESSES` (true).## WARNING: Setting this to `true` results in indexed data no longer being backwards compatible with# the ENS Subgraph. For full data-level backwards compatibility with the ENS Subgraph, set this to `false`.HEAL_REVERSE_ADDRESSES=true
# A feature flag to enable or disable the indexing of additional Resolver record values# Optional. If this is set to true, ENSIndexer will track additional Resolver record values.# If this is not set, the default value is set to `DEFAULT_INDEX_ADDITIONAL_RESOLVER_RECORDS` (true).## WARNING: It is unsafe to assume that indexed resolver record values are equivalent to the# result of performing dynamic forward resolution via the ENS protocol, as naively retrieving resolver# record values from indexed data is not ENSIP-10 nor CCIP-Read compliant. At this time we do _not_# recommend anyone directly using the indexed resolver record values; Features are planned in the# ENSNode roadmap that will provide safe use of indexed resolver record values (in appropriate contexts).## NOTE:# - Setting this to `true` results in indexed data being a strict _superset_ of subgraph data.# For exact subgraph data compatibility, set this to `false`.# - For protocol acceleration of forward or reverse resolution lookups, set this to `true`.INDEX_ADDITIONAL_RESOLVER_VALUES=true
# Controls ENSIndexer's handling of Literal Labels and Literal Names# This configuration only applies to the Subgraph datamodel and Subgraph Compatible GraphQL API responses.## Optional. If this is not set, the default value is set to `DEFAULT_REPLACE_UNNORMALIZED` (true).## When set to true, all Literal Labels and Literal Names encountered by ENSIndexer will be Interpreted.# - https://ensnode.io/docs/reference/terminology#interpreted-label# - https://ensnode.io/docs/reference/terminology#interpreted-name## That is,# 1) all Labels stored and returned by ENSIndexer will either be normalized or represented as an Encoded# LabelHash, and# 2) all Names stored and returned by ENSIndexer will either be normalized or consist of Labels that# may be represented as an Encoded LabelHash of the Literal Label value found onchain.## When set to false, ENSIndexer will store and return Literal Labels and Literal Names without further# interpretation.# - https://ensnode.io/docs/reference/terminology#literal-label# - https://ensnode.io/docs/reference/terminology#literal-name## NOTE: REPLACE_UNNORMALIZED must be `false` for subgraph compatible indexing behavior.REPLACE_UNNORMALIZED=true