diff --git a/src/cmap/connect.ts b/src/cmap/connect.ts
index ff143e27471..32c5d81524d 100644
--- a/src/cmap/connect.ts
+++ b/src/cmap/connect.ts
@@ -25,7 +25,6 @@ import {
   type ConnectionOptions,
   CryptoConnection
 } from './connection';
-import type { ClientMetadata } from './handshake/client_metadata';
 import {
   MAX_SUPPORTED_SERVER_VERSION,
   MAX_SUPPORTED_WIRE_VERSION,
@@ -180,7 +179,7 @@ export interface HandshakeDocument extends Document {
   ismaster?: boolean;
   hello?: boolean;
   helloOk?: boolean;
-  client: ClientMetadata;
+  client: Document;
   compression: string[];
   saslSupportedMechs?: string;
   loadBalanced?: boolean;
@@ -197,11 +196,12 @@ export async function prepareHandshakeDocument(
   const options = authContext.options;
   const compressors = options.compressors ? options.compressors : [];
   const { serverApi } = authContext.connection;
+  const clientMetadata = await options.extendedMetadata;
 
   const handshakeDoc: HandshakeDocument = {
     [serverApi?.version ? 'hello' : LEGACY_HELLO_COMMAND]: 1,
     helloOk: true,
-    client: options.metadata,
+    client: clientMetadata,
     compression: compressors
   };
 
diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts
index b5aaf3ff8f9..a8155125976 100644
--- a/src/cmap/connection.ts
+++ b/src/cmap/connection.ts
@@ -133,6 +133,8 @@ export interface ConnectionOptions
   socketTimeoutMS?: number;
   cancellationToken?: CancellationToken;
   metadata: ClientMetadata;
+  /** @internal */
+  extendedMetadata: Promise<Document>;
 }
 
 /** @internal */
diff --git a/src/cmap/handshake/client_metadata.ts b/src/cmap/handshake/client_metadata.ts
index fb1ba40b14e..8940823c48a 100644
--- a/src/cmap/handshake/client_metadata.ts
+++ b/src/cmap/handshake/client_metadata.ts
@@ -1,7 +1,8 @@
+import { promises as fs } from 'fs';
 import * as os from 'os';
 import * as process from 'process';
 
-import { BSON, Int32 } from '../../bson';
+import { BSON, type Document, Int32 } from '../../bson';
 import { MongoInvalidArgumentError } from '../../error';
 import type { MongoOptions } from '../../mongo_client';
 
@@ -71,13 +72,13 @@ export class LimitedSizeDocument {
     return true;
   }
 
-  toObject(): ClientMetadata {
+  toObject(): Document {
     return BSON.deserialize(BSON.serialize(this.document), {
       promoteLongs: false,
       promoteBuffers: false,
       promoteValues: false,
       useBigInt64: false
-    }) as ClientMetadata;
+    });
   }
 }
 
@@ -153,7 +154,57 @@ export function makeClientMetadata(options: MakeClientMetadataOptions): ClientMe
     }
   }
 
-  return metadataDocument.toObject();
+  return metadataDocument.toObject() as ClientMetadata;
+}
+
+let dockerPromise: Promise<boolean>;
+/** @internal */
+async function getContainerMetadata() {
+  const containerMetadata: Record<string, any> = {};
+  dockerPromise ??= fs.access('/.dockerenv').then(
+    () => true,
+    () => false
+  );
+  const isDocker = await dockerPromise;
+
+  const { KUBERNETES_SERVICE_HOST = '' } = process.env;
+  const isKubernetes = KUBERNETES_SERVICE_HOST.length > 0 ? true : false;
+
+  if (isDocker) containerMetadata.runtime = 'docker';
+  if (isKubernetes) containerMetadata.orchestrator = 'kubernetes';
+
+  return containerMetadata;
+}
+
+/**
+ * @internal
+ * Re-add each metadata value.
+ * Attempt to add new env container metadata, but keep old data if it does not fit.
+ */
+export async function addContainerMetadata(originalMetadata: ClientMetadata) {
+  const containerMetadata = await getContainerMetadata();
+  if (Object.keys(containerMetadata).length === 0) return originalMetadata;
+
+  const extendedMetadata = new LimitedSizeDocument(512);
+
+  const extendedEnvMetadata = { ...originalMetadata?.env, container: containerMetadata };
+
+  for (const [key, val] of Object.entries(originalMetadata)) {
+    if (key !== 'env') {
+      extendedMetadata.ifItFitsItSits(key, val);
+    } else {
+      if (!extendedMetadata.ifItFitsItSits('env', extendedEnvMetadata)) {
+        // add in old data if newer / extended metadata does not fit
+        extendedMetadata.ifItFitsItSits('env', val);
+      }
+    }
+  }
+
+  if (!('env' in originalMetadata)) {
+    extendedMetadata.ifItFitsItSits('env', extendedEnvMetadata);
+  }
+
+  return extendedMetadata.toObject();
 }
 
 /**
diff --git a/src/connection_string.ts b/src/connection_string.ts
index 5a197ad4dea..bb2fc6e8db3 100644
--- a/src/connection_string.ts
+++ b/src/connection_string.ts
@@ -6,7 +6,7 @@ import { URLSearchParams } from 'url';
 import type { Document } from './bson';
 import { MongoCredentials } from './cmap/auth/mongo_credentials';
 import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './cmap/auth/providers';
-import { makeClientMetadata } from './cmap/handshake/client_metadata';
+import { addContainerMetadata, makeClientMetadata } from './cmap/handshake/client_metadata';
 import { Compressor, type CompressorName } from './cmap/wire_protocol/compression';
 import { Encrypter } from './encrypter';
 import {
@@ -550,6 +550,9 @@ export function parseOptions(
   );
 
   mongoOptions.metadata = makeClientMetadata(mongoOptions);
+  mongoOptions.extendedMetadata = addContainerMetadata(mongoOptions.metadata).catch(() => {
+    /* rejections will be handled later */
+  });
 
   return mongoOptions;
 }
diff --git a/src/mongo_client.ts b/src/mongo_client.ts
index 6c37f3de293..69463638278 100644
--- a/src/mongo_client.ts
+++ b/src/mongo_client.ts
@@ -757,6 +757,8 @@ export interface MongoOptions
   writeConcern: WriteConcern;
   dbName: string;
   metadata: ClientMetadata;
+  /** @internal */
+  extendedMetadata: Promise<Document>;
   /**
    * @deprecated This option will be removed in the next major version.
    */
diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts
index d45acf6249b..3005adb49e8 100644
--- a/src/sdam/topology.ts
+++ b/src/sdam/topology.ts
@@ -143,6 +143,7 @@ export interface TopologyOptions extends BSONSerializeOptions, ServerOptions {
   directConnection: boolean;
   loadBalanced: boolean;
   metadata: ClientMetadata;
+  extendedMetadata: Promise<Document>;
   /** MongoDB server API version */
   serverApi?: ServerApi;
   [featureFlag: symbol]: any;
diff --git a/test/integration/connection-monitoring-and-pooling/connection.test.ts b/test/integration/connection-monitoring-and-pooling/connection.test.ts
index 731a1415502..a4827dabc8e 100644
--- a/test/integration/connection-monitoring-and-pooling/connection.test.ts
+++ b/test/integration/connection-monitoring-and-pooling/connection.test.ts
@@ -1,6 +1,7 @@
 import { expect } from 'chai';
 
 import {
+  addContainerMetadata,
   connect,
   Connection,
   type ConnectionOptions,
@@ -36,7 +37,8 @@ describe('Connection', function () {
         const connectOptions: Partial<ConnectionOptions> = {
           connectionType: Connection,
           ...this.configuration.options,
-          metadata: makeClientMetadata({ driverInfo: {} })
+          metadata: makeClientMetadata({ driverInfo: {} }),
+          extendedMetadata: addContainerMetadata(makeClientMetadata({ driverInfo: {} }))
         };
 
         connect(connectOptions as any as ConnectionOptions, (err, conn) => {
@@ -60,7 +62,8 @@ describe('Connection', function () {
           connectionType: Connection,
           monitorCommands: true,
           ...this.configuration.options,
-          metadata: makeClientMetadata({ driverInfo: {} })
+          metadata: makeClientMetadata({ driverInfo: {} }),
+          extendedMetadata: addContainerMetadata(makeClientMetadata({ driverInfo: {} }))
         };
 
         connect(connectOptions as any as ConnectionOptions, (err, conn) => {
@@ -92,7 +95,8 @@ describe('Connection', function () {
         const connectOptions: Partial<ConnectionOptions> = {
           connectionType: Connection,
           ...this.configuration.options,
-          metadata: makeClientMetadata({ driverInfo: {} })
+          metadata: makeClientMetadata({ driverInfo: {} }),
+          extendedMetadata: addContainerMetadata(makeClientMetadata({ driverInfo: {} }))
         };
 
         connect(connectOptions as any as ConnectionOptions, (err, conn) => {
diff --git a/test/tools/cmap_spec_runner.ts b/test/tools/cmap_spec_runner.ts
index 4c11736857e..76d1d4e4d46 100644
--- a/test/tools/cmap_spec_runner.ts
+++ b/test/tools/cmap_spec_runner.ts
@@ -4,6 +4,7 @@ import { clearTimeout, setTimeout } from 'timers';
 import { promisify } from 'util';
 
 import {
+  addContainerMetadata,
   CMAP_EVENTS,
   type Connection,
   ConnectionPool,
@@ -371,6 +372,7 @@ async function runCmapTest(test: CmapTest, threadContext: ThreadContext) {
   }
 
   const metadata = makeClientMetadata({ appName: poolOptions.appName, driverInfo: {} });
+  const extendedMetadata = addContainerMetadata(metadata);
   delete poolOptions.appName;
 
   const operations = test.operations;
@@ -382,7 +384,12 @@ async function runCmapTest(test: CmapTest, threadContext: ThreadContext) {
   const mainThread = threadContext.getThread(MAIN_THREAD_KEY);
   mainThread.start();
 
-  threadContext.createPool({ ...poolOptions, metadata, minPoolSizeCheckFrequencyMS });
+  threadContext.createPool({
+    ...poolOptions,
+    metadata,
+    extendedMetadata,
+    minPoolSizeCheckFrequencyMS
+  });
   // yield control back to the event loop so that the ConnectionPoolCreatedEvent
   // has a chance to be fired before any synchronously-emitted events from
   // the queued operations
diff --git a/test/unit/cmap/connect.test.ts b/test/unit/cmap/connect.test.ts
index c636c0cd81a..19c44b50cac 100644
--- a/test/unit/cmap/connect.test.ts
+++ b/test/unit/cmap/connect.test.ts
@@ -2,6 +2,7 @@ import { expect } from 'chai';
 import { promisify } from 'util';
 
 import {
+  addContainerMetadata,
   CancellationToken,
   type ClientMetadata,
   connect,
@@ -24,6 +25,7 @@ const CONNECT_DEFAULTS = {
   generation: 1,
   monitorCommands: false,
   metadata: {} as ClientMetadata,
+  extendedMetadata: addContainerMetadata({} as ClientMetadata),
   loadBalanced: false
 };
 
@@ -207,7 +209,162 @@ describe('Connect Tests', function () {
     });
   });
 
-  context('prepareHandshakeDocument', () => {
+  describe('prepareHandshakeDocument', () => {
+    describe('client environment (containers and FAAS)', () => {
+      const cachedEnv = process.env;
+
+      context('when only kubernetes is present', () => {
+        let authContext;
+
+        beforeEach(() => {
+          process.env.KUBERNETES_SERVICE_HOST = 'I exist';
+          authContext = {
+            connection: {},
+            options: {
+              ...CONNECT_DEFAULTS,
+              extendedMetadata: addContainerMetadata({} as ClientMetadata)
+            }
+          };
+        });
+
+        afterEach(() => {
+          if (cachedEnv.KUBERNETES_SERVICE_HOST != null) {
+            process.env.KUBERNETES_SERVICE_HOST = cachedEnv.KUBERNETES_SERVICE_HOST;
+          } else {
+            delete process.env.KUBERNETES_SERVICE_HOST;
+          }
+          authContext = {};
+        });
+
+        it(`should include { orchestrator: 'kubernetes'} in client.env.container`, async () => {
+          const handshakeDocument = await prepareHandshakeDocument(authContext);
+          expect(handshakeDocument.client.env.container.orchestrator).to.equal('kubernetes');
+        });
+
+        it(`should not have 'name' property in client.env `, async () => {
+          const handshakeDocument = await prepareHandshakeDocument(authContext);
+          expect(handshakeDocument.client.env).to.not.have.property('name');
+        });
+
+        context('when 512 byte size limit is exceeded', async () => {
+          it(`should not 'env' property in client`, async () => {
+            // make metadata = 507 bytes, so it takes up entire LimitedSizeDocument
+            const longAppName = 's'.repeat(493);
+            const longAuthContext = {
+              connection: {},
+              options: {
+                ...CONNECT_DEFAULTS,
+                extendedMetadata: addContainerMetadata({ appName: longAppName })
+              }
+            };
+            const handshakeDocument = await prepareHandshakeDocument(longAuthContext);
+            expect(handshakeDocument.client).to.not.have.property('env');
+          });
+        });
+      });
+
+      context('when kubernetes and FAAS are both present', () => {
+        let authContext;
+
+        beforeEach(() => {
+          process.env.KUBERNETES_SERVICE_HOST = 'I exist';
+          authContext = {
+            connection: {},
+            options: {
+              ...CONNECT_DEFAULTS,
+              extendedMetadata: addContainerMetadata({ env: { name: 'aws.lambda' } })
+            }
+          };
+        });
+
+        afterEach(() => {
+          if (cachedEnv.KUBERNETES_SERVICE_HOST != null) {
+            process.env.KUBERNETES_SERVICE_HOST = cachedEnv.KUBERNETES_SERVICE_HOST;
+          } else {
+            delete process.env.KUBERNETES_SERVICE_HOST;
+          }
+          authContext = {};
+        });
+
+        it(`should include { orchestrator: 'kubernetes'} in client.env.container`, async () => {
+          const handshakeDocument = await prepareHandshakeDocument(authContext);
+          expect(handshakeDocument.client.env.container.orchestrator).to.equal('kubernetes');
+        });
+
+        it(`should still have properly set 'name' property in client.env `, async () => {
+          const handshakeDocument = await prepareHandshakeDocument(authContext);
+          expect(handshakeDocument.client.env.name).to.equal('aws.lambda');
+        });
+
+        context('when 512 byte size limit is exceeded', async () => {
+          it(`should not have 'container' property in client.env`, async () => {
+            // make metadata = 507 bytes, so it takes up entire LimitedSizeDocument
+            const longAppName = 's'.repeat(447);
+            const longAuthContext = {
+              connection: {},
+              options: {
+                ...CONNECT_DEFAULTS,
+                extendedMetadata: {
+                  appName: longAppName,
+                  env: { name: 'aws.lambda' }
+                } as unknown as Promise<Document>
+              }
+            };
+            const handshakeDocument = await prepareHandshakeDocument(longAuthContext);
+            expect(handshakeDocument.client.env.name).to.equal('aws.lambda');
+            expect(handshakeDocument.client.env).to.not.have.property('container');
+          });
+        });
+      });
+
+      context('when container nor FAAS env is not present (empty string case)', () => {
+        const authContext = {
+          connection: {},
+          options: { ...CONNECT_DEFAULTS }
+        };
+
+        context('when process.env.KUBERNETES_SERVICE_HOST = undefined', () => {
+          beforeEach(() => {
+            delete process.env.KUBERNETES_SERVICE_HOST;
+          });
+
+          afterEach(() => {
+            afterEach(() => {
+              if (cachedEnv.KUBERNETES_SERVICE_HOST != null) {
+                process.env.KUBERNETES_SERVICE_HOST = cachedEnv.KUBERNETES_SERVICE_HOST;
+              } else {
+                delete process.env.KUBERNETES_SERVICE_HOST;
+              }
+            });
+          });
+
+          it(`should not have 'env' property in client`, async () => {
+            const handshakeDocument = await prepareHandshakeDocument(authContext);
+            expect(handshakeDocument.client).to.not.have.property('env');
+          });
+        });
+
+        context('when process.env.KUBERNETES_SERVICE_HOST is an empty string', () => {
+          beforeEach(() => {
+            process.env.KUBERNETES_SERVICE_HOST = '';
+          });
+
+          afterEach(() => {
+            if (cachedEnv.KUBERNETES_SERVICE_HOST != null) {
+              process.env.KUBERNETES_SERVICE_HOST = cachedEnv.KUBERNETES_SERVICE_HOST;
+            } else {
+              delete process.env.KUBERNETES_SERVICE_HOST;
+            }
+          });
+
+          it(`should not have 'env' property in client`, async () => {
+            const handshakeDocument = await prepareHandshakeDocument(authContext);
+            expect(handshakeDocument.client).to.not.have.property('env');
+          });
+        });
+      });
+    });
+
     context('when serverApi.version is present', () => {
       const options = {
         authProviders: new MongoClientAuthProviders()
diff --git a/test/unit/cmap/connection_pool.test.js b/test/unit/cmap/connection_pool.test.js
index a08c955d14d..1f3f20178fa 100644
--- a/test/unit/cmap/connection_pool.test.js
+++ b/test/unit/cmap/connection_pool.test.js
@@ -22,6 +22,9 @@ describe('Connection Pool', function () {
         },
         s: {
           authProviders: new MongoClientAuthProviders()
+        },
+        options: {
+          extendedMetadata: {}
         }
       }
     }