The published Urdu video lesson is available alongside this written guide. Use the corrected source snapshot and the version notes below when reproducing the MongoDB example.
Laravel Docker Lessons · Lesson 7
Connect Laravel to MongoDB using separate username and password settings, and install the native PHP driver and locked dependencies entirely inside Docker.
Corrected recording snapshot: use lesson-7.1. This revision replaces the original host-extension preparation and connection-string configuration. The written guide is available before the recorded video.
This corrected lesson configures MongoDB using separate host, port, database, username, password and authentication-database settings. PHP, the MongoDB extension and Composer dependency installation all run inside Docker. Windows needs Docker Desktop and the source files; it needs no PHP installation, Composer installation or MongoDB DLL for this demonstration.
Use the corrected lesson-7.1 snapshot for recording. The original lesson-7 remains historical. Current main also has the corrected connection settings, together with later lessons' tooling. This revised Lesson 7 Dockerfile uses Composer temporarily during the image build and removes its executable afterward. Lesson 8 separately introduces Composer as a permanent container tool.
Keep both Compose files
Keep docker-compose.yaml as the base PHP/Nginx/MySQL setup and create docker-compose.mongodb.yaml as its sibling. Pass both files to every command. Do not overwrite the base with the MongoDB override. SQL remains the default connection for users, sessions and queues; MongoNote explicitly selects the named MongoDB connection.
Prepare all files shown in this article before startup: Dockerfile, .dockerignore, the Composer manifest and lock file, .env.example, config/database.php, both Compose files, model, console command, route and Blade view. Use the exact lock file from lesson-7.1. The Docker context excludes host vendor, and the image installs its own locked dependencies.
Configure username and password separately
The private environment uses these local tutorial defaults:
MONGODB_HOST=mongo MONGODB_PORT=27017 MONGODB_DATABASE=laravel_demo MONGODB_USERNAME=lesson MONGODB_PASSWORD=local-mongo-password MONGODB_AUTH_DATABASE=admin config/database.php reads host, port, database, username, password and options.authSource; it does not read a connection URL. The driver receives credentials separately, so passwords containing reserved characters do not need URL encoding. The authentication database is admin because this local example uses the root user initialized by the official image. The application collection lives in laravel_demo.
The Compose override injects these named settings into web and uses the same username/password to initialize MongoDB. mongo:27017 is an internal Docker address, with no published MongoDB host port. Use private credentials and a restricted application user for a real deployment. Set your chosen username/password before initializing a new data volume. Changing initialization variables does not update users already stored in an existing database; preserve any data you need.
Complete files to prepare before startup
Save every file below before running the Docker commands. The base and MongoDB Compose files are separate. All code comes from the corrected lesson-7.1 tag.
Download the matching composer.lock together with composer.json. Composer install honors that lock; changing only the manifest does not update the lock.
docker-compose.yaml
x-laravel-environment: &laravel-environment DB_URL: "" DB_SOCKET: "" DB_CONNECTION: mysql DB_HOST: db DB_PORT: 3306 DB_DATABASE: laravel_app DB_USERNAME: root DB_PASSWORD: root QUEUE_CONNECTION: database DB_QUEUE_RETRY_AFTER: 90 x-laravel-service: &laravel-service build: context: . dockerfile: Dockerfile image: my-laravel-app working_dir: /var/www/html user: "www-data" volumes: - .:/var/www/html - /var/www/html/vendor - /var/www/html/storage - /var/www/html/bootstrap/cache environment: <<: *laravel-environment SCHEDULER_DEMO_ENABLED: "false" depends_on: db: condition: service_healthy services: web: <<: *laravel-service scheduler: <<: *laravel-service profiles: ["scheduler"] init: true command: ["php", "artisan", "schedule:work", "--no-interaction"] restart: unless-stopped environment: <<: *laravel-environment CACHE_STORE: file SCHEDULER_DEMO_ENABLED: "true" worker: <<: *laravel-service profiles: ["queue"] init: true command: ["php", "artisan", "queue:work", "database", "--queue=emails", "--sleep=1", "--tries=3", "--timeout=30", "--max-time=3600", "--no-interaction"] restart: unless-stopped stop_grace_period: 45s nginx: image: nginx:latest ports: - "${APP_PORT:-8080}:80" volumes: - .:/var/www/html:ro - ./.docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - web db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: laravel_app ports: - "${DB_FORWARD_PORT:-3308}:3306" volumes: - dbdata:/var/lib/mysql healthcheck: test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -p\"$${MYSQL_ROOT_PASSWORD}\" --silent"] interval: 5s timeout: 5s retries: 20 start_period: 20s volumes: dbdata: docker-compose.mongodb.yaml
services: web: environment: MONGODB_HOST: mongo MONGODB_PORT: 27017 MONGODB_DATABASE: ${MONGODB_DATABASE:-laravel_demo} MONGODB_USERNAME: ${MONGODB_USERNAME:-lesson} MONGODB_PASSWORD: ${MONGODB_PASSWORD:-local-mongo-password} MONGODB_AUTH_DATABASE: ${MONGODB_AUTH_DATABASE:-admin} depends_on: mongo: condition: service_healthy mongo: image: mongo:8.0 environment: MONGO_INITDB_ROOT_USERNAME: ${MONGODB_USERNAME:-lesson} MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD:-local-mongo-password} volumes: - mongodata:/data/db healthcheck: test: ["CMD-SHELL", "mongosh --quiet --host 127.0.0.1 --username \"$${MONGO_INITDB_ROOT_USERNAME}\" --password \"$${MONGO_INITDB_ROOT_PASSWORD}\" --authenticationDatabase admin --eval 'quit(db.adminCommand({ping:1}).ok ? 0 : 1)'"] interval: 5s timeout: 10s retries: 20 start_period: 20s volumes: mongodata: Dockerfile
FROM php:8.2-fpm WORKDIR /var/www/html RUN apt-get update && apt-get install -y \ libzip-dev \ libpq-dev \ unzip \ && docker-php-ext-install zip pdo_mysql pdo_pgsql pcntl \ && rm -rf /var/lib/apt/lists/* RUN pecl install mongodb-1.21.2 \ && docker-php-ext-enable mongodb COPY --from=composer:2 /usr/bin/composer /tmp/composer.phar COPY --chown=www-data:www-data . /var/www/html RUN COMPOSER_ALLOW_SUPERUSER=1 COMPOSER_HOME=/tmp/composer-build php /tmp/composer.phar install --no-interaction --prefer-dist --optimize-autoloader \ && chown -R www-data:www-data vendor storage bootstrap/cache \ && chmod -R 775 storage bootstrap/cache \ && rm -f /tmp/composer.phar \ && rm -rf /tmp/composer-build .dockerignore
.git .env .env.* !.env.example node_modules vendor output .phpunit.cache bootstrap/cache/*.php public/hot database/*.sqlite* storage/logs/* storage/framework/cache/data/* storage/framework/sessions/* storage/framework/views/* composer.json
{ "$schema": "https://getcomposer.org/schema.json", "name": "laravel/laravel", "type": "project", "description": "The skeleton application for the Laravel framework.", "keywords": [ "laravel", "framework" ], "license": "MIT", "require": { "php": "^8.2", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1", "mongodb/laravel-mongodb": "^5.11" }, "require-dev": { "fakerphp/faker": "^1.23", "laravel/pail": "^1.2.2", "laravel/pint": "^1.24", "laravel/sail": "^1.41", "mockery/mockery": "^1.6", "nunomaduro/collision": "^8.6", "pestphp/pest": "^3.8", "pestphp/pest-plugin-laravel": "^3.2" }, "autoload": { "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/" } }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } }, "scripts": { "setup": [ "composer install", "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"", "@php artisan key:generate", "@php artisan migrate --force", "npm install", "npm run build" ], "dev": [ "Composer\\Config::disableProcessTimeout", "npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --timeout=0\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others" ], "test": [ "@php artisan config:clear --ansi", "@php artisan test" ], "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover --ansi" ], "post-update-cmd": [ "@php artisan vendor:publish --tag=laravel-assets --ansi --force" ], "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ "@php artisan key:generate --ansi", "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"", "@php artisan migrate --graceful --ansi" ], "pre-package-uninstall": [ "Illuminate\\Foundation\\ComposerScripts::prePackageUninstall" ] }, "extra": { "laravel": { "dont-discover": [] } }, "config": { "optimize-autoloader": true, "preferred-install": "dist", "sort-packages": true, "allow-plugins": { "pestphp/pest-plugin": true, "php-http/discovery": true } }, "minimum-stability": "stable", "prefer-stable": true } .env.example
APP_NAME=Laravel APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://localhost # Lesson 4: opt in only while recording/running the test-user example. SCHEDULER_DEMO_ENABLED=false APP_LOCALE=en APP_FALLBACK_LOCALE=en APP_FAKER_LOCALE=en_US APP_MAINTENANCE_DRIVER=file # APP_MAINTENANCE_STORE=database # PHP_CLI_SERVER_WORKERS=4 BCRYPT_ROUNDS=12 LOG_CHANNEL=stack LOG_STACK=single LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug DB_CONNECTION=sqlite # DB_HOST=127.0.0.1 # DB_PORT=3306 # DB_DATABASE=laravel # DB_USERNAME=root # DB_PASSWORD= # Lesson 7: optional MongoDB connection; SQL remains the default database. MONGODB_HOST=mongo MONGODB_PORT=27017 MONGODB_DATABASE=laravel_demo MONGODB_USERNAME=lesson MONGODB_PASSWORD=local-mongo-password MONGODB_AUTH_DATABASE=admin SESSION_DRIVER=database SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=null BROADCAST_CONNECTION=log FILESYSTEM_DISK=local QUEUE_CONNECTION=database CACHE_STORE=database # CACHE_PREFIX= MEMCACHED_HOST=127.0.0.1 REDIS_CLIENT=phpredis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_MAILER=log MAIL_SCHEME=null MAIL_HOST=127.0.0.1 MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" # Lesson 5: copy these credentials from your Mailtrap Email Sandbox, not Email Sending. # The queued demo explicitly uses the mailtrap mailer with the MAIL_* keys above. # For Lesson 5, set MAIL_HOST=sandbox.smtp.mailtrap.io and private Sandbox credentials. AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" config/database.php
<?php use Illuminate\Support\Str; use Pdo\Mysql; return [ /* |-------------------------------------------------------------------------- | Default Database Connection Name |-------------------------------------------------------------------------- | | Here you may specify which of the database connections below you wish | to use as your default connection for database operations. This is | the connection which will be utilized unless another connection | is explicitly specified when you execute a query / statement. | */ 'default' => env('DB_CONNECTION', 'sqlite'), /* |-------------------------------------------------------------------------- | Database Connections |-------------------------------------------------------------------------- | | Below are all of the database connections defined for your application. | An example configuration is provided for each database system which | is supported by Laravel. You're free to add / remove connections. | */ 'connections' => [ 'mongodb' => [ 'driver' => 'mongodb', 'host' => env('MONGODB_HOST', 'mongo'), 'port' => (int) env('MONGODB_PORT', 27017), 'database' => env('MONGODB_DATABASE', 'laravel_demo'), 'username' => env('MONGODB_USERNAME', 'lesson'), 'password' => env('MONGODB_PASSWORD', 'local-mongo-password'), 'options' => [ 'authSource' => env('MONGODB_AUTH_DATABASE', 'admin'), 'serverSelectionTimeoutMS' => 5000, 'connectTimeoutMS' => 5000, ], ], 'sqlite' => [ 'driver' => 'sqlite', 'url' => env('DB_URL'), 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), 'busy_timeout' => null, 'journal_mode' => null, 'synchronous' => null, 'transaction_mode' => 'DEFERRED', ], 'mysql' => [ 'driver' => 'mysql', 'url' => env('DB_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'laravel'), 'username' => env('DB_USERNAME', 'root'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => env('DB_CHARSET', 'utf8mb4'), 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ (PHP_VERSION_ID >= 80500 ? Mysql::ATTR_SSL_CA : PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'), ]) : [], ], 'mariadb' => [ 'driver' => 'mariadb', 'url' => env('DB_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'laravel'), 'username' => env('DB_USERNAME', 'root'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => env('DB_CHARSET', 'utf8mb4'), 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ (PHP_VERSION_ID >= 80500 ? Mysql::ATTR_SSL_CA : PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'), ]) : [], ], 'pgsql' => [ 'driver' => 'pgsql', 'url' => env('DB_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '5432'), 'database' => env('DB_DATABASE', 'laravel'), 'username' => env('DB_USERNAME', 'root'), 'password' => env('DB_PASSWORD', ''), 'charset' => env('DB_CHARSET', 'utf8'), 'prefix' => '', 'prefix_indexes' => true, 'search_path' => 'public', 'sslmode' => env('DB_SSLMODE', 'prefer'), ], 'sqlsrv' => [ 'driver' => 'sqlsrv', 'url' =><...