Connecting to Couchbase Capella and the bucket you type in
A managed endpoint carries neither a port nor a bucket path, so the scheme supplies the port and the TLS mode while the bucket is typed by hand and nothing is invented for it.
Paste a Couchbase Capella connection string into the dialog to connect and one field stays empty. The form does not fill it, does not guess at it, and will not let the connection be saved until you type something into it. That field is the bucket, and the empty box is the correct behaviour rather than a gap in the parser.
The string Capella hands you looks like this:
couchbases://cb.abc123.cloud.couchbase.com
There is a scheme and a host. There is no port and no path. Everything the form shows after the paste was derived from those two things, and everything it does not show was not derivable.
What a Couchbase Capella connection string sets, and what it does not
The paste is decomposed into discrete fields before the provider ever sees it
(connection-string-parser.ts:138). Three inputs come out of the URL above:
| Input | host | port | database (bucket) |
|---|---|---|---|
couchbase://localhost:8091/travel |
localhost |
8091 |
travel |
couchbase://user:pw@node1,node2/travel |
node1, first host wins |
8091 |
travel |
couchbases://cb.abc123.cloud.couchbase.com |
the host | 18091 |
none, not invented |
The scheme does two jobs. It selects the management port - 8091 for
couchbase://, 18091 for couchbases:// - and it arrives as an SSL mode:
require for couchbases://, disable for couchbase://. The second half of
that is load-bearing, because the transport picks https over http from
config.ssl alone and never re-reads the pasted string. Without the mode being
set from the scheme, a couchbases:// paste posted plain HTTP to port 18091,
which is a connection failure that looks like a network problem and is not one.
require and not a verifying mode, for the same reason it is require on
PostgreSQL and MySQL here: a self-hosted Couchbase node ships a self-signed
certificate, and a default that refused it would be a default nobody could use on
their own cluster. Capella is the case where you should change it. Its
certificate is signed by a public root, so verify-system verifies against the
trust store the runtime already has, with no PEM to go looking for. That is one
dropdown change.
What the scheme does not set is the query endpoint. It cannot: the URL has no information about it.
Why the pasted port is deliberately ignored
A connection carries one port, and Couchbase needs two endpoints - a management
one and a query one. Only the management port is stored. The query endpoint is
discovered at runtime from GET /pools/default/nodeServices, reading
nodesExt[].services.n1ql, or n1qlSSL under TLS, and preferring
alternateAddresses.external where the cluster publishes one. That preference is
exactly what makes NAT, Docker port mapping and Capella work, because in all
three the address the cluster knows about itself is not the address you reach it
on. With no n1ql entry anywhere, the transport falls back to 8093 or 18093.
Which is why a port in the pasted URL is thrown away rather than used. A
couchbase:// URL copied out of an application config carries the KV port - the
binary protocol’s port, 11210 - not the management port. Storing it would put it
in the management field, and every management call would go to a service that
does not speak REST. The URL’s hostname is lifted out for the transport, the
scheme sets the port and the SSL mode, and discovery handles the rest
(couchbase/index.ts:368).
A Capella hostname given without an explicit port is also an SRV record, so it is
resolved through _couchbases._tcp.<host> first; a DNS failure or an empty answer
falls back to a plain A record, which is what every self-hosted cluster needs.
The bucket that has to be typed
The connection’s database field carries the bucket. That is the one field on
this engine that surprises people, so the form stops calling it a database: for
type === 'couchbase' the label reads Bucket (ConnectionModal.tsx:139). A
connection without one is rejected before it is attempted, with the message
naming the field it means:
Couchbase requires a bucket (use the "database" field)
A managed endpoint carries neither a port nor a bucket path, so the bucket must
be entered by hand and nothing is invented for it, and one connection still
covers exactly one bucket. Picking the first
bucket the cluster lists would be a guess that works until the day someone has
two, and multi-bucket browsing from one connection is out of scope:
getSchemaList() and every monitoring read are scoped to config.database. If
you work across three buckets, you make three connections.
What the connection does have below the bucket is two more levels. Cluster,
bucket, scope and collection is four levels against a schema explorer that draws
a flat list, so scope and collection are flattened the way PostgreSQL flattens
schema and table: the default scope is implicit and everything else is
qualified. hotel in the default scope, inventory.hotel outside it. The
collection list comes from system:keyspaces LEFT JOIN system:scopes - LEFT,
because system:scopes does not list _default on Server 8.0.2, and an inner
join would silently drop every collection in the default scope.
Identifier quoting is a boundary, not a style
Once the bucket is set, every generated statement concatenates it into a keyspace
path. SQL++ has no bind parameter for an identifier, so there is no placeholder
to hide behind; the path is assembled as text. quoteIdentifier() therefore
doubles any backtick embedded in a name (keyspace.ts:31), so an identifier
cannot terminate its own quoting and have the remainder of itself parsed as
SQL++. That is a security property, not a formatting habit, which is why the
quoting lives in one pure module rather than at each call site.
There is a second, more mundane reason the backticks are always there. bucket
and scope are reserved words in SQL++, and an unquoted projection over
system:keyspaces fails with error 3000 - verified on Server 8.0.2. The catalog
read that lists your collections is itself a statement that needs the quoting.
The same rule shapes what the collection-open query looks like. SELECT * FROM hotel nests the document under the keyspace name and omits the key entirely, so
generated queries alias the keyspace and project the key explicitly:
SELECT META(d).id AS __id, d.* FROM `travel`.`inventory`.`hotel` AS d LIMIT 50;
Confirming the connection reached the query service
Connecting proves less than it looks like it proves. connect() issues one
GET /pools/default - the cheapest call that needs no RBAC role beyond cluster
read - which establishes that the host is reachable and the credentials are
accepted. It says nothing about the query service, because the query endpoint has
not been discovered yet at that point.
So run one statement. Opening any collection from the explorer does it, or type
the statement above by hand. A row coming back is proof that discovery resolved a
query node, that TLS negotiated if you are on couchbases://, and that the
credentials carry SELECT on the keyspace - three separate things that a green
connection dot does not cover.
Read the result carefully rather than the status code. The Query Service returns
syntax and semantic errors inside an HTTP 200 response, with status: "errors"
in the payload, so the transport inspects the body before the HTTP code
(http-transport.ts:249). Skipping that check reports a failed statement as
“0 rows”, which is the most expensive kind of wrong answer an editor can give.
That first row will not be stale. Every statement is sent with
scan_consistency: "request_plus", so you see your own writes. Verified against
Couchbase Server 8.0.2 Community Edition: immediately after an INSERT, a
SELECT returned zero rows while COUNT(*) already returned three, and the same
SELECT returned three rows seconds later. The default costs latency on a
write-heavy cluster, because the query waits for the index to catch up, and
callers opt out per statement with { scanConsistency: 'not_bounded' }.
Capella is the cloud vendor this provider is documented against. Its management APIs - allowed-IP administration, cluster provisioning - are not covered here, and neither are Analytics, Full-Text Search or Eventing. The transport and the default port for this engine are on the engine list, and the container that has to sit close enough to the cluster to reach it at all is the subject of getting started.