Watch Aspire live streamsDocsTry Aspire

Solr hosting integration

⭐ Community Toolkit

The Solr hosting integration adds a SolrResource representing a container and its selected core. See Get started with the Solr integration for the architecture and Connect with the Solr integration for consuming-app examples.

Install 📦 CommunityToolkit.Aspire.Hosting.Solr in the AppHost:

Aspire CLI — Add CommunityToolkit.Aspire.Hosting.Solr package
aspire add communitytoolkit-solr

The Aspire CLI is interactive, be sure to select the appropriate search result when prompted:

Aspire CLI — Example output prompt
Select an integration to add:
> communitytoolkit-solr (CommunityToolkit.Aspire.Hosting.Solr)
> Other results listed as selectable options...

The package has stable releases. Use version 13.6.1 when you need to pin it.

For a TypeScript AppHost, add the package to the configuration to generate its bindings:

aspire.config.json
{
"packages": {
"CommunityToolkit.Aspire.Hosting.Solr": "13.6.1"
}
}

Add a resource named solr with a core named documents. Reference it from an ASP.NET Core project named Api. Add a project reference in the C# AppHost to generate Projects.Api.

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const solr = await builder.addSolr('solr', { coreName: 'documents' });
const api = await builder.addProject('api', '../Api/Api.csproj');
await api.withReference(solr);
await api.waitFor(solr);
await builder.build().run();

The default image is docker.io/library/solr:10.0.0. The http endpoint targets container port 8983; the host port is dynamically allocated. The default core name is solr, independent of the resource name.

Without a custom configset, the container runs solr-precreate {coreName}. The connection string includes the selected core’s path.

Use a named volume to retain indexes and configuration outside the container lifecycle. Optionally specify a host port for local tools:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const solr = await builder.addSolr('solr', {
port: 8983,
coreName: 'documents',
});
await solr.withDataVolume({ name: 'solr-data' });
await builder.build().run();

The volume mounts at /var/solr. Omitting name generates a volume name based on the application and resource names. The optional isReadOnly argument defaults to false.

Prepare a host directory writable by the Solr container process, which uses UID 8983. Prefer setting directory ownership or granting appropriate access over making the directory world-writable.

The following examples assume that solr-data already exists beside the AppHost and has suitable permissions:

apphost.mts
import { fileURLToPath } from 'node:url';
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const dataDirectory = fileURLToPath(new URL('./solr-data/', import.meta.url));
const solr = await builder.addSolr('solr', { coreName: 'documents' });
await solr.withDataBindMount(dataDirectory);
await builder.build().run();

The bind mount targets /var/solr and also accepts isReadOnly, defaulting to false. Do not mount both a data volume and a bind mount at that target.

Prepare a valid configset directory, including its conf directory, at configsets/documents beside the AppHost. Add it to the resource:

apphost.mts
import { fileURLToPath } from 'node:url';
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const configSetPath = fileURLToPath(
new URL('./configsets/documents/', import.meta.url)
);
const solr = await builder.addSolr('solr', { coreName: 'documents' });
await solr.withConfigset('documents-config', configSetPath);
await builder.build().run();

Required arguments:

  • configSetName: The name inside /opt/solr/server/solr/configsets.
  • configSetPath: The host path of the configset directory. Use an absolute path to avoid working-directory ambiguity.

The helper adds a SolrConfigSetAnnotation and a bind mount at /opt/solr/server/solr/configsets/{configSetName}. Startup uses solr-create -c {coreName} -d {configSetName} instead of solr-precreate. If multiple configset annotations are added, startup selects the last one.

The integration registers {resourceName}_check. It requests /solr/{coreName}/admin/ping and expects HTTP 200. The check verifies that the selected core responds to ping. Configure its ping handler when supplying a custom configset.

Use WaitFor on dependent apps to wait for this health check during local orchestration. A resource reference alone does not delay app startup.

C# APITypeScript APIBehavior
AddSolr(name, port = null, coreName = null)addSolr(name, { port, coreName })Add a container. name is required; host port is allocated and core name is solr when omitted.
WithConfigset(configSetName, configSetPath)withConfigset(configSetName, configSetPath)Mount the required configset directory and select it for core creation.
WithDataVolume(name = null, isReadOnly = false)withDataVolume({ name, isReadOnly })Mount a named volume at /var/solr.
WithDataBindMount(source, isReadOnly = false)withDataBindMount(source, { isReadOnly })Mount the required host data directory at /var/solr.

SolrResource exposes PrimaryEndpoint, Host, Port, CoreName, ConnectionStringExpression, and UriExpression. TypeScript exposes endpoint and expression getters as primaryEndpoint(), host(), port(), connectionStringExpression(), and uriExpression(). The exported mutable core property uses coreName.get() and coreName.set(value).

Set the core name when adding the resource rather than mutating the property afterward. Startup arguments and the health-check path capture the original name, while the connection expression reads CoreName.

The connection string and Uri property are http://{host}:{port}/solr/{coreName}. A reference also supplies Host, Port, and CoreName. See Solr connection properties for exact variable names.