# earthdata-search: the NASA application behind a planet's worth of science data

> Earthdata Search is the NASA EOSDIS web application that lets researchers find, compare, visualise and download Earth science data, and its repository holds the React front end, the serverless Lambda layer and the CDK infrastructure that deploys it to AWS. It suits a developer building a tool on top of the CMR search API, and it is a poor fit if you want a simple client library rather than the whole search interface.

**nasa/earthdata-search** — Earthdata Search is a web application developed by NASA EOSDIS to enable data discovery, search, comparison, visualization, and access across EOSDIS' Earth Science data holdings.

- Repository: https://github.com/nasa/earthdata-search
- Website: https://search.earthdata.nasa.gov
- Stars: 829 · Forks: 261
- Language: JavaScript
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/nasa-earthdata-search

## A search interface built on four NASA services

Earthdata Search is a web application developed by NASA EOSDIS to enable data discovery, search, comparison, visualization and access across the EOSDIS Earth Science data holdings.

This repository is not the data. It is the interface to the data, and the interface is a client of other services that EOSDIS runs. The README names them.

The Common Metadata Repository provides the data discovery and access layer, and it is the piece that matters most, because CMR is a public search API over the holdings. Earthdata Login provides the authentication, so a user's NASA account is the identity. The Global Imagery Browse Services provide the visualization, which is the thumbnail and map imagery you see for each result. And a number of OPeNDAP services hosted by data providers give the actual subsetting and download of the data itself.

So the division of labour is clean. CMR knows what exists, Earthdata Login knows who you are, GIBS shows you what it looks like, and the provider's OPeNDAP service hands you the bytes.

The audience for the repository is therefore a developer who wants to build on this, either by running the application locally to develop against it, or by deploying it. The live application is at search.earthdata.nasa.gov, and the project is primarily JavaScript with a React front end.

The last push to the repository was on 2026-10-19, there are no GitHub releases, and the licence story needs a note that is covered further down.

## The AWS shape behind the front end

The application installation section says the app uses NodeJS and Vite to generate static assets, and that the serverless application utilises a list of AWS services, with a parenthetical warning that this matters if you are deploying to an AWS environment.

The list is S3, SQS, Step Functions, API Gateway, Lambda, CloudWatch Events and Bedrock.

That is a modern serverless architecture and the mapping is fairly direct. The React application is built with Vite into static assets and served from S3, with the README strongly recommending CloudFront in front of S3. API Gateway fronts the serverless functions, and the Lambda directory in the repository holds that code. SQS carries the retrieval requests as messages, Step Functions orchestrates the multi step retrieval workflow, CloudWatch Events triggers the scheduled jobs, and Bedrock provides the natural language search capability.

The SQS part changes what the user experiences. A data retrieval from a large archive is not an HTTP request that completes in a second. It is a job. The application hands the retrieval to the queue, a Lambda picks it up, and the result is delivered later, which is why the application has to model retrieval status at all.

The repository reflects that structure. There is a cdk directory with the AWS CDK application that synthesises the infrastructure, a serverless directory for the Lambda code, a layers directory for shared Lambda layers, migrations for the database schema, and a portals directory for the themed variants of the interface that the project calls portals, built by a script called build-available-portals.

## Node, PostgreSQL and an SQS emulator come before the app

The prerequisites section is the longest part of the README, and that is a signal about the shape of the project. This is a full stack application with a database, a queue and a cloud provider integration, and the local environment has to approximate all three.

Node is managed with Node Version Manager, and the README recommends the shell integration so the version switches automatically per directory. The version comes from a .nvmrc in the repository root, and a single command picks it up.

```bash
nvm use
```

PostgreSQL is required because Earthdata Search uses PostgreSQL in production on AWS RDS. The recommended install is Homebrew, followed by starting the service and creating the default user.

```bash
brew install postgresql
brew services start postgresql
createuser -s postgres
```

Docker is optional and is used to simulate SQS locally with ElasticMQ, which is how the queue behaviour is reproduced on a laptop without touching AWS.

Valkey is optional and only needed for the image cache and the NLP search. The README is specific about the migration from Redis, since the two share a port.

```bash
brew install valkey
brew services start valkey
```

```bash
brew services stop redis
brew uninstall redis
```

The instruction to ensure port 6379 is clear before starting Valkey is not decoration, because the docker-compose file in the repository root maps exactly that port.

```yaml
services:
  valkey:
    image: valkey/valkey:latest
    ports:
      - "6379:6379"
```

There are npm scripts for running the cache in a container instead, npm run start:cache and npm run stop:cache, which is the way to avoid the port conflict entirely.

## Two config files, and one of them you must not commit

The configuration model is the part of the setup most likely to waste an afternoon, and it comes down to two files with different rules.

The first is the secrets file. For local development Earthdata Search uses a json configuration file to store secure files, an example is provided, and it should be copied and completed before going any further.

To operate against a local database this file needs dbUsername and dbPassword set, and the README adds that you may need to update dbHost, dbName or databasePort in static.config.json if you have custom local configuration. If you created the postgres user after a fresh PostgreSQL install, both values are the username you use to log into your computer, which is a detail that saves a confusing authentication failure.

The second file is the public one, and it has an unusual rule attached. Non-secure values are stored in static.config.json, and to prevent conflicts amongst developers you copy the static config into overrideStatic.config.json and change the values there. Do not commit changes to static.config.json.

```bash
cp static.config.json overrideStatic.config.json
```

So the tracked file is a shared default, the override file is yours, and the difference between them is how two developers can change a setting without colliding in version control. The same pattern appears for the environment file, where an example is copied and completed, and the README notes that connecting to AWS Bedrock means changing the values set to CHANGE-ME.

The environment file also carries the feature flags that decide what the local application does, and those are worth knowing before you start rather than after.

```bash
USE_CACHE=false
USE_GEOCODER=false
USE_NLP_SEARCH=false
SKIP_SQS=true
```

USE_CACHE turns on the local Valkey instance for caching GIBS images and geocoder results, and SKIP_SQS, which is true by default, means retrievals are not added to the queue and are not submitted without a manual Lambda invocation. The default local run is therefore a search interface that does not actually order data.

## npm start brings up the React app and a mock API Gateway

Running the application is one command, and it starts more than the application.

```bash
npm start
```

The README says this will start everything you need to run Earthdata Search locally, and then lists what that is. The React application is on port 8080. There is a Mock API Gateway on port 3001. The serverless directory is watched for code changes, and an ElasticMQ container provides the SQS queues, with a Mock SQS service to trigger the Lambdas when messages arrive.

That is a well thought out local approximation of the production topology. The API Gateway is mocked so that the front end can talk to the same shape of endpoint it will talk to in AWS, and ElasticMQ stands in for SQS so that the asynchronous retrieval flow, with its queue and its triggered Lambdas, behaves the way it will in production.

The package.json shows how much is wired together. The build:api script bundles the serverless code with esbuild through a script called esbuild.js, and watch:api runs nodemon over the serverless source for JavaScript, TypeScript and GraphQL. The start:api script runs nodemon with dotenvx and a synthesized CloudFormation template from the CDK output directory, which is how the local Lambda code knows which AWS resources it is supposed to be talking to. And start:elasticmq runs the softwaremill ElasticMQ image with ports 9324 and 9325 and a configuration file mounted from the repository.

The CDK piece is the one that surprises people. The preinstall script installs dependencies inside the cdk/earthdata-search directory, and the run-synth script synthesises the CDK application. The local development environment is therefore built on top of the same infrastructure definition that deploys to AWS, which is the reason the mock API Gateway can be faithful at all.

## Migrations, the geocoder, and a legal note about the licence

The database has its own two step setup. First you create the database, then you run the migrations.

```bash
createdb edsc_dev
```

```bash
npm run invoke-local migrateDatabase
```

And there is a command for adding a new migration, with a warning that it exists so that the migration follows the same timestamp name scheme. The migration name is supplied as an argument when you run it.

The migrations directory in the repository is where those files live, and the migrate script is node-pg-migrate, so the tool is a conventional one rather than something bespoke.

The geocoder is a separate optional service with its own Dockerfile, geocoder.Dockerfile, and its own npm script that builds the image and runs it on port 4001 with the AWS credentials passed in from the environment. The USE_GEOCODER flag controls whether it is used at all.

Now the licence, which is the one place where the documentation is genuinely ambiguous. The licence recorded for the repository is a custom one that GitHub cannot classify, with a pointer to the LICENSE file. The README, by contrast, carries the standard NASA Apache 2.0 notice, with copyright held by the United States Government as represented by the Administrator of the National Aeronautics and Space Administration, dated 2007 to 2024.

Those are not necessarily contradictory, since a repository can carry a mixed set of licences with a LICENSE file that explains which applies to which part. But the README does not explain it, and the metadata does not match, so if you are going to redistribute code from this repository you should read the LICENSE file itself rather than either of the two summaries.

The other documentation gap worth naming is the absence of GitHub releases. The build badge, the codecov badge and the Snyk known vulnerabilities badge are all in the README, so the project is being tested and scanned, but there is no version history to pin against, and the package.json version is 1.0.0 regardless of what has actually shipped.

## Conclusion

earthdata-search suits a developer who needs the full Earthdata Search interface, with its collection comparison, its GIBS imagery preview and its access workflow, either by running it locally against CMR or by deploying the same stack to AWS. It does not suit someone who only needs to query the Common Metadata Repository, because CMR is a separate public service and the far smaller path to that is a direct HTTP call. Before you deploy it, read the licensing note in the README rather than the licence badge, since the repository metadata calls the licence custom while the README states Apache 2.0 with NASA copyright, and expect the local environment to take real setup, since it needs PostgreSQL, a Node version pinned in .nvmrc, an SQS emulator and, for the cache and search features, a local Valkey instance on port 6379.

## FAQ

### What is NASA Earthdata Search?

It is a web application developed by NASA EOSDIS to enable data discovery, search, comparison, visualization and access across the EOSDIS Earth Science data holdings. It is built on the Common Metadata Repository, Earthdata Login, the Global Imagery Browse Services and provider hosted OPeNDAP services.

### What do I need to run earthdata-search locally?

Node managed through NVM with the version from the .nvmrc, a local PostgreSQL instance, and npm install. Docker is optional and is used to run ElasticMQ as a local SQS emulator, and Valkey is optional and needed for the image cache and NLP search features.

### How do I set up the configuration files?

Copy secret.config.json.example to secret.config.json for credentials including dbUsername and dbPassword, copy static.config.json to overrideStatic.config.json for non-secure values and do not commit changes to static.config.json, and copy .env.example to .env, changing the values set to CHANGE-ME if you want to connect to AWS Bedrock.

### How do I run the database migrations?

Create the database with createdb edsc_dev, then run npm run invoke-local migrateDatabase. To add a new migration use the npm run migrate create command with the migration name as its argument, which keeps the timestamp naming scheme.

### What does SKIP_SQS do in the local environment?

When set to true it skips adding retrievals to SQS, so your retrievals are not submitted without a manual Lambda invocation. The .env.example ships with SKIP_SQS=true, USE_CACHE=false, USE_GEOCODER=false and USE_NLP_SEARCH=false.

## Sources

- [Issues](https://github.com/nasa/earthdata-search/issues)
- [nasa/earthdata-search on GitHub](https://github.com/nasa/earthdata-search)
- [Project website](https://search.earthdata.nasa.gov)
- [README](https://github.com/nasa/earthdata-search/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nasa-earthdata-search
