Hi.
I have a private link set up pointing to a PostgreSQL database running on AWS. The private link service itself is already provisioned and configured on the BTP side. What I need to understand is how to wire this up properly in a CAP Node.js project.
Does @cap-js/postgres automatically route queries through the private link once the service is bound to the app, or does it need additional configuration to know it should use that network path?
I also added the private link service as a requires entry in the SRV module inside mta.yaml, so the binding is there at runtime. But I am not sure if that alone is enough for CAP to pick up the database connection through it, since there is no standard PostgreSQL service instance, just the private link binding exposing the endpoint.
Is binding it in mta.yaml the right approach, or is there something else needed on the CAP or adapter level to make this work end to end?
server.js
mta
Requires SRV with private link
package.json
#privatelink #btp #capnodejs #cap #postgres #postgresoncap
Request clarification before answering.
Hello @Willem_Pardaens
I did it this way and it worked.
1. Add the Private Link Service Binding
In your mta.yaml, add the Private Link service instance as a resource and bind it to your CAP service module:
modules:
- name: your-cap-srv
requires:
- name: my-privatelink-postgres
resources:
- name: my-privatelink-postgres
type: org.cloudfoundry.existing-serviceThis binding makes the Private Link credentials available inside VCAP_SERVICES at runtime, under the privatelink key.
2. Install the PostgreSQL adapter
cds add postgres --for productionand
npm install3. Configure cds.requires in package.json
Set the database kind to postgres. Credentials will be injected at runtime via server.js:
{
"[production]": {
"db": {
"kind": "postgres"
}
},
}4. Create server.js
At the root of your CAP project, create a server.js file. It reads the Private Link hostname from VCAP_SERVICES and the remaining credentials from User-Provided Variables, then injects everything into cds.env.requires.db before the app starts:
"use strict";
const cds = require("@sap/cds");
cds.on("bootstrap", (app) => {
const LOG = cds.log("server");
if (process.env.VCAP_SERVICES) {
const vcap = JSON.parse(process.env.VCAP_SERVICES);
const pl = (vcap["privatelink"] || []).find(
(s) => s.name === "ipp-privatelink-dev"
);
if (pl?.credentials?.hostname) {
cds.env.requires.db = cds.env.requires.db || {};
cds.env.requires.db.credentials = {
host: pl.credentials.hostname,
port: Number(process.env.DB_PORT),
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
schema: process.env.DB_SCHEMA,
ssl: { rejectUnauthorized: false },
};
}
} else {
LOG.info("[DB] VCAP_SERVICES não presente — ambiente local (SQLite)");
}
});host is not set manually — it comes from the Private Link binding credential (pl.credentials.hostname). All other values come from environment variables, keeping secrets out of source code.5. Set the User-Provided Variables in BTP Cockpit
Go to your application in BTP Cockpit → User-Provided Variables and create the following entries:
PL_SERVICE_NAME | Name of the Private Link service instance (e.g. privatelink) |
DB_PORT | PostgreSQL port, typically 5432 |
DB_USER | Database user |
DB_PASSWORD | Database password |
DB_DATABASE | Database name |
DB_SCHEMA | Schema name (e.g. public) |
The variable names do not need to match exactly — they just need to be consistent with what process.env.<VARIABLE_NAME> reads in server.js.
After adding or changing any variable, restart the application for the changes to take effect:
cf restart <your-app-name>
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you for the response, I'll test it and I'll come back with the answer if it works.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 9 | |
| 5 | |
| 4 | |
| 4 | |
| 4 | |
| 3 | |
| 3 | |
| 2 | |
| 2 | |
| 2 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.