Compare cross-project search and cross-cluster search
Cross-project search (CPS) provides Elastic Cloud Serverless with cross-project search capabilities similar to cross-cluster search (CCS).
Both features let you search data across multiple deployments from a single request, but the query syntax, default scope, and configuration requirements are different. In general, CPS reduces setup overhead and simplifies queries by searching all linked projects by default.
This page highlights the key differences and shows side-by-side query examples to help you transition from CCS to CPS.
The following sections describe how CCS and CPS differ in availability, setup, query syntax, and scope behavior.
- Availability
- CCS is for Elasticsearch clusters on self-managed, Elastic Cloud Enterprise, Elastic Cloud on Kubernetes, and Elastic Cloud Hosted deployments. CPS is for Elastic Cloud Serverless projects. Use CCS when searching across clusters and CPS when searching across serverless projects.
- Prerequisites and configuration
- CCS requires remote cluster connectivity and security configuration across clusters. CPS only requires project linking in the Elastic Cloud UI, with no transport-layer setup. For details, refer to CCS prerequisites and CPS prerequisites.
- Cross-environment support
- CCS can connect clusters across organizations and infrastructure boundaries. CPS is limited to projects within the same Elastic Cloud organization.
- Default search scope
- In CCS, a query runs against the local cluster only unless you explicitly include remote clusters. In CPS, a query runs against the origin project and all linked projects by default, so you don't need to rewrite queries as you link additional projects.
- Naming
- CCS uses remote cluster names as prefixes. CPS uses project aliases. Project aliases are derived from the project's connection alias, while remote cluster names come from the cluster settings configuration.
- Referencing the local cluster or origin project
- In CCS, the local cluster appears as
(local)in search responses and has no explicit prefix in query expressions. If no prefix is provided, the query runs against the local cluster only. In CPS, the origin project appears as_originin responses and can be targeted with the_origin:prefix in query expressions. - Missing resources
- In CCS, searching for an index that doesn't exist on a cluster returns an error unless
ignore_unavailableis set totrue. In CPS, unqualified expressions succeed as long as the target resource exists in at least one searched project. Projects that don't have the resource are silently skipped, which means queries work without error even when projects have different index sets. Qualified expressions behave like CCS: if you target a specific project and the resource is missing, the request returns an error. For details, refer to Search in CPS. - Selecting which clusters or projects to search
- In CCS, you select which clusters to search by listing cluster names or using wildcards on cluster names in the index expression. CPS introduces project routing, which selects projects based on project metadata, including project aliases, cloud provider, region, and custom tags. Project routing supports boolean logic (
AND,OR,NOT), grouping with parentheses, and reusable named expressions. Routing is evaluated before the query runs, so excluded projects are never searched. CPS also provides a scope selector in Kibana apps for controlling which projects are searched without modifying queries.
The following tables summarize how common search tasks translate between CCS and CPS for Query DSL and ES|QL. The CCS examples assume a local cluster with a remote cluster named cluster_one. The CPS examples assume an origin project with a linked project whose alias is linked_project.
For full examples, refer to the examples section.
| Task | CCS | CPS |
|---|---|---|
| Search local/origin only | GET my-index/_search |
GET _origin:my-index/_search |
| Search one remote/linked | GET cluster_one:my-index/_search |
GET linked_project:my-index/_search |
| Search all | GET my-index,*:my-index/_search |
GET my-index/_search (default) |
| Exclude one | GET my-index,*:my-index,-cluster_one:*/_search |
GET my-index,-linked_project:*/_search |
| Route by metadata | Not available | project_routing |
| Identify origin in responses | (local) in _clusters; no prefix in _index |
_origin in _clusters; no prefix in _index |
| Identify remote/linked in responses | cluster_one:my-index in _index |
linked_project:my-index in _index |
| Task | CCS | CPS |
|---|---|---|
| Search local/origin only | FROM my-index |
FROM _origin:my-index |
| Search one remote/linked | FROM cluster_one:my-index |
FROM linked_project:my-index |
| Search all | FROM my-index,cluster_one:my-index |
FROM my-index (default) |
| Exclude one | FROM my-index,*:my-index,-cluster_one:* |
FROM my-index,-linked_project:* |
| Route by metadata | Not available | SET project_routing |
| Identify origin in responses | No prefix in METADATA _index |
No prefix in METADATA _index |
| Identify remote/linked in responses | cluster_one:my-index in METADATA _index |
linked_project:my-index in METADATA _index |
The following examples compare equivalent tasks in CCS and CPS. The CCS examples assume a local cluster with a remote cluster named cluster_one. The CPS examples assume an origin project with a linked project whose alias is linked_project.
Restrict a query to a single cluster or project without including results from remote clusters or linked projects. Use this when you need to isolate results to one cluster or project, for example when debugging a local issue.
In CCS, a plain index name targets the local cluster only. No prefix is needed.
_search
GET my-index/_search
ES|QL
FROM my-index
| LIMIT 10
In CPS, a plain index name searches all projects. To restrict to the origin project, use the _origin: prefix.
_search
GET _origin:my-index/_search
ES|QL
FROM _origin:my-index
| LIMIT 10
Target a specific remote cluster or linked project. Use this when you want to check data from a single cluster or project without pulling in results from others.
Prefix the index with the remote cluster name.
_search
GET cluster_one:my-index/_search
ES|QL
FROM cluster_one:my-index
| LIMIT 10
Prefix the index with the linked project alias.
_search
GET linked_project:my-index/_search
ES|QL
FROM linked_project:my-index
| LIMIT 10
Search an index across every available cluster or project at once. Use this when you want to correlate data from all clusters or projects, for example during an incident investigation that spans multiple clusters or projects.
List the local index and each remote cluster explicitly, or use a wildcard for remote clusters.
_search
GET my-index,cluster_one:my-index/_search
Or, using a wildcard to include all remote clusters:
GET my-index,*:my-index/_search
ES|QL
List each cluster explicitly in the FROM command.
FROM my-index,cluster_one:my-index
| LIMIT 10
Use the index name with no prefix. All linked projects are searched by default.
_search
GET my-index/_search
ES|QL
FROM my-index
| LIMIT 10
Search broadly but skip one or more clusters or projects. Use this when you need results from most clusters or projects but want to leave some out, for example to exclude development or staging projects. In CPS, because all projects are searched by default, you only need to specify what to skip.
Prefix the cluster name with - and use * in the index position. You can chain multiple exclusions.
_search
GET my-index,*:my-index,-cluster_one:*,-cluster_two:*/_search
ES|QL
FROM my-index,*:my-index,-cluster_one:*,-cluster_two:*
| LIMIT 10
Use the same - prefix with the project alias. An exclusion pattern requires a preceding inclusion pattern. You can exclude multiple projects.
_search
GET my-index,-linked_project:*,-staging_project:*/_search
ES|QL
FROM my-index,-linked_project:*,-staging_project:*
| LIMIT 10
Determine which cluster or project returned a specific document. Use this when you want to trace a result back to its source when searching across multiple clusters or projects.
In both CCS and CPS, the _index field in the response indicates where each document originated.
Documents from a remote cluster include the cluster name as a prefix: cluster_one:my-index. Documents from the local cluster have no prefix: my-index.
_search
GET my-index,cluster_one:my-index/_search
Example response:
{
"hits": {
"hits": [
{ "_index": "my-index", "_id": "1", "_source": { "message": "local doc" } },
{ "_index": "cluster_one:my-index", "_id": "2", "_source": { "message": "remote doc" } }
]
},
...
}
ES|QL
Use METADATA _index to include the field:
FROM my-index,cluster_one:my-index METADATA _index
| KEEP _index, message
| LIMIT 10
Example results:
{
"columns": [
{ "name": "_index", "type": "keyword" },
{ "name": "message", "type": "keyword" }
],
"values": [
[ "my-index", "local doc" ],
[ "cluster_one:my-index", "remote doc" ]
]
}
Documents from a linked project include the project alias as a prefix: linked_project:my-index. Documents from the origin project have no prefix: my-index.
_search
GET my-index/_search
Example response:
{
"hits": {
"hits": [
{ "_index": "my-index", "_id": "1", "_source": { "message": "origin doc" } },
{ "_index": "linked_project:my-index", "_id": "2", "_source": { "message": "linked doc" } }
]
},
...
}
ES|QL
Use METADATA _index to include the field:
FROM my-index METADATA _index
| KEEP _index, message
| LIMIT 10
Example results:
{
"columns": [
{ "name": "_index", "type": "keyword" },
{ "name": "message", "type": "keyword" }
],
"values": [
[ "my-index", "origin doc" ],
[ "linked_project:my-index", "linked doc" ]
]
}
You can also use project tags like _project._alias in METADATA (ES|QL) or fields (_search) to identify the source project directly, without parsing the _index prefix.
Route a query to a subset of projects based on project metadata like cloud provider, region, or custom tags, rather than using the index expression alone. This capability is new in CPS and has no CCS equivalent.
In CCS, you select clusters by naming them in the index expression. You can't route queries based on cluster metadata.
_search
GET cluster_one:logs-*,cluster_two:logs-*/_search
ES|QL
FROM cluster_one:logs-*,cluster_two:logs-*
| STATS COUNT(*) BY service.name
In CPS, use project_routing to select projects dynamically. Project routing supports boolean logic (AND, OR, NOT) and wildcards.
_search
GET logs-*/_search
{
"project_routing": "_csp:aws AND _region:us*"
}
ES|QL
SET project_routing="_csp:aws AND _region:us*";
FROM logs-*
| STATS COUNT(*) BY service.name
You can also define reusable named expressions and reference them with the @ prefix:
_search
GET logs-*/_search
{
"project_routing": "@us-aws"
}
ES|QL
SET project_routing="@us-aws";
FROM logs-*
| STATS COUNT(*) BY service.name
If you're evaluating Elastic Cloud Serverless, refer to the following resources:
- Compare Elastic Cloud Hosted and Serverless: Learn more about the differences between Elastic Cloud Serverless and other Elasticsearch offerings.
- Elastic Cloud Serverless: An introduction to Elastic Cloud Serverless and its features.
- Start a free trial: Explore the product with a free trial of Elastic Cloud Serverless.
- Migrate your Elasticsearch data: Learn about options for migrating between Elasticsearch deployment types, including how to migrate to Elastic Cloud Serverless.