⚡️ 30-Second Quick Start (Copy/Paste and Run)
docker run -d --name oracle-free -p 1521:1521 \
-v oracle-data:/opt/oracle/oradata \
-e ORACLE_PWD=OracleIsAwesome \
container-registry.oracle.com/database/free:latest-lite
This starts Oracle 23ai Free instantly — no VM, no installer, no configuration. Just run and connect.
☁️ Pre-Flight Checklist
Before we taxi down the runway, here’s your flight plan. Keep this handy to navigate your flight path. Welcome aboard the cloud!
🌥️ Takeoff
⛅️ Cruising Altitude
- 4 Ways to Connect to Your New Database
- Managing Your Database Container
- Understanding Data Persistence: Your Data is Safe
- Best Practice: Create a Dedicated Developer User
🌤️ Landing & Taxi
- Why 23ai Might Be the Only Database You Need
- Conclusion
- Bonus: Faster Connections with Shell Shortcuts
Enjoy your flight! ☁️
For years, developers on macOS have faced a common hurdle: running Oracle Database locally meant clunky VMs, slow performance, and a drain on system resources. Personally, the thought of setting up a dedicated environment or firing up my UTM Linux VM was always daunting.
Thankfully, that's not the case anymore.
Oracle's Oracle Database 23ai Free is available as a native ARM64 container image for Apple Silicon (M1–M4). This allows developers to run a full Oracle Database locally on macOS using Docker—no emulation, no VMs, and no workarounds. It makes Oracle feel as easy to spin up as Postgres for my FastAPI projects, and that’s a huge improvement for local development.
Why This Changes Everything
Before this release, the developer experience was painful:
- No Native Support: Oracle databases required an x86 architecture, forcing Mac users to run a heavy Linux VM.
- Slow and Inefficient: Virtualization is resource-intensive, leading to slow startup times, high RAM usage, and significant battery drain.
- Complex Setup: Configuring VMs and networking was a constant source of friction.
Now, with the native ARM64 container, you get:
- Significantly faster startup: Running natively on Apple Silicon eliminates emulation overhead and reduces startup time to under a minute.
- Reduced resource usage: No full VM means dramatically lower CPU/RAM consumption and smoother performance.
- Simplified workflow: It behaves like any standard Docker container—pull, run, connect, done.
Prerequisites
- An Apple Silicon Mac: (M1, M2, M3, M4, etc.)
- Docker Desktop: Make sure it's installed and running.
Get Started in 60 Seconds: The Docker Command
Open your terminal and run this single command. Replace <your-password> with a password of your choice.
docker run -d --name oracle-free -p 1521:1521 \
-v oracle-data:/opt/oracle/oradata \
-e ORACLE_PWD=<your-password> \
container-registry.oracle.com/database/free:latest-lite
Example:
docker run -d --name oracle-free -p 1521:1521 \
-v oracle-data:/opt/oracle/oradata \
-e ORACLE_PWD=OracleIsAwesome \
container-registry.oracle.com/database/free:latest-lite
What does -d do?
The -d flag runs the container in detached mode, meaning it runs in the background without blocking your terminal. With -d, the container starts in the background and you can continue using your terminal immediately.
For first-time setup, some developers prefer to see the startup logs in real-time to confirm everything is working. If that's you, omit the -d flag:
docker run --name oracle-free -p 1521:1521 \
-v oracle-data:/opt/oracle/oradata \
-e ORACLE_PWD=OracleIsAwesome \
container-registry.oracle.com/database/free:latest-lite
Without -d, the container runs in the foreground and you'll see all the logs directly as the database initializes. Wait for the message DATABASE IS READY TO USE! to appear.
🌩️ Important: If you run without
-d, pressingCtrl + Cwill stop the container entirely. If this happens, don't worry—just restart it in the background:# 1. Start the container in the background docker start oracle-free # 2. Confirm the container is running (check the STATUS column) docker ps # 3. Follow the logs to see when the database is ready docker logs -f oracle-freeOnce you see
DATABASE IS READY TO USE!, pressCtrl + Cto exit the log view. This time, the container will keep running in the background because it was started withdocker start.
What does -e ORACLE_PWD do?
The -e flag sets an environment variable inside the container. ORACLE_PWD sets the initial password for the SYS and SYSTEM administrative users. If you omit this, the container won't start.
What does -v oracle-data:/opt/oracle/oradata do?
The -v flag is crucial for data persistence. It creates a Docker named volume called oracle-data and maps it to the /opt/oracle/oradata directory inside the container—the location where Oracle stores its database files.
This separates your data from the container's lifecycle. If you stop, remove, or update the oracle-free container, the oracle-data volume remains safely on your system. Without this line, all data and schema changes would be lost forever when the container is removed.
Checking When Your Database is Ready
If you started the container in detached mode (with -d), you can check the startup progress anytime:
# Follow the logs to see when the database is ready
docker logs -f oracle-free
Wait for the logs to display the message: DATABASE IS READY TO USE!
Once you see this message, press Ctrl + C to exit the log view. The container will keep running in the background.
4 Ways to Connect to Your New Database
Once the container is running, you can connect to it using your favorite SQL tool.
Your Connection Cheat Sheet
No matter which tool you use, these are your connection details:
| Item | Value |
|---|---|
| Host | localhost |
| Port | 1521 |
| Service Name | freepdb1 |
| Admin Users |
system (default) or sys (requires AS SYSDBA) |
| Password | The one you set (e.g., OracleIsAwesome) |
| Connect String | localhost:1521/freepdb1 |
# Quick Copy/Paste Connection Defaults
HOST=localhost
PORT=1521
SERVICE_NAME=freepdb1
# Admin users (created automatically)
SYSTEM / <your-password>
SYS / <your-password> (connect as SYSDBA if needed)
Why freepdb1? The Oracle container uses a Multitenant Architecture.
CDB (Container Database -
FREE): This is the root database that manages the overall instance. You rarely connect here for development.PDB (Pluggable Database -
freepdb1): This is an isolated, independent database running inside the CDB. For all application development, you should connect to the PDB.
🌩️ Practical takeaway: For all development work, always connect to
freepdb1, not the root container.
A Quick Note: SYS, SYSTEM, and AS SYSDBA
You will often see AS SYSDBA in Oracle documentation. Here’s a simple guide:
SYS User: The true superuser. It owns the database's core data dictionary and can do anything. To connect as SYS, you must use the AS SYSDBA clause, which activates system-level privileges. It's used for fundamental operations like starting or stopping the database.
SYSTEM User: A default administrator account with extensive rights, but less powerful than SYS. It's practical for administrative tasks like creating new users (as shown later).
AS SYSDBA: This is a special privilege, not a user. It tells the database you're connecting with the highest level of authority.
🌩️ Rule of Thumb: Use
SYS AS SYSDBAonly when necessary. For creating users or granting general permissions,SYSTEMis fine. For application work, always use a dedicated, non-admin user.
1. For the CLI Fans: SQLcl
If you prefer the command line, Oracle SQLcl is the modern tool of choice.
-
Install SQLcl:
brew install sqlcl -
Add SQLcl to your PATH:
Note: The version number (25.3.0.274.1210) might be different for you. Check the correct path in/opt/homebrew/Caskroom/sqlcl/.
echo 'export PATH=/opt/homebrew/Caskroom/sqlcl/25.3.0.274.1210/sqlcl/bin:$PATH' >> ~/.zshrc -
Reload your terminal configuration:
source ~/.zshrc -
Confirm it's working:
sql -v
Connecting with SQLcl
Once installed, connecting is a one-liner:
# Connect as the default admin user
# (good for creating other users)
sql system/OracleIsAwesome@localhost:1521/freepdb1
# Or, connect as the superuser for powerful database operations
sql sys/OracleIsAwesome@localhost:1521/freepdb1 as sysdba
2. Connect Using the Built-In SQL*Plus (No Installation Needed)
The Docker container comes with the classic SQL*Plus tool pre-installed. You can use docker exec to run it directly from your Mac's terminal without installing any client software or even entering the container's shell.
Run this single command on your terminal:
# As the default admin user
docker exec -it oracle-free sqlplus system/OracleIsAwesome@localhost:1521/freepdb1
# As the superuser
docker exec -it oracle-free sqlplus sys/OracleIsAwesome@localhost:1521/freepdb1 as sysdba
Or, if you created your dedicated developer user:
docker exec -it oracle-free sqlplus dev/DevPassword123@localhost:1521/freepdb1
This command directly connects you to the database and drops you into an interactive SQL*Plus session.
3. For the GUI Lovers: SQL Developer
If you prefer a graphical interface, use the free SQL Developer.
- Download: Oracle SQL Developer Downloads
- Click the
+icon to create a new connection. - Fill in the details from the cheat sheet above.
- Click Test. If it says "Success," click Connect.
4. For the VS Code Enthusiasts: Oracle SQL Developer Extension
- In VS Code, go to the Extensions marketplace and search for "Oracle SQL Developer Extension for VS Code".
- Install the official extension from Oracle.
- Click the Oracle Database icon in the activity bar.
- Click the
Create Connectionbutton. - Fill in the connection details. Crucially, make sure you select
Service Namefor the connection type, notSID. - Click Connect. You can now browse your schema and run queries directly from VS Code.
Test your Connection
Once connected, you have a couple of ways to interact with your database directly within VS Code:
SQL Worksheet: Right-click on your connection in the Oracle Database panel and select Open New SQL Worksheet. This opens a standard editor where you can write and execute queries.
SQLcl Terminal: Right-click the connection and choose Open SQLcl in Terminal. This launches an integrated terminal running Oracle's modern command-line interface, SQLcl. You may be prompted to enter your password (e.g OracleIsAwesome).
To test your connection, open a worksheet or SQLcl session and run this simple query:
-- Test your connection with a simple query!
SELECT 'Connected in VS Code!' AS status FROM dual;
You should see the result directly in VS Code, confirming your setup is complete.
When you're done, you can right-click the connection and select Disconnect.
The next time you want to use it, simply click the connection name again.
If you didn't save your password during setup, VS Code will prompt you for it before reconnecting. However, if you checked the "Save Password" box when creating the connection, it will reconnect instantly with a single click.
Managing Your Database Container
Your container, named oracle-free, persists on your system. You don't need to run the docker run command again.
-
Start the database:
docker start oracle-free -
Stop the database:
docker stop oracle-free -
Check if it's running:
docker ps -
View live logs (useful for debugging):
docker logs -f oracle-free -
"Remove Everything" Cleanup Commands
# Completely remove the container (does not delete your data volume) docker rm oracle-free # Remove the container and its stored data docker rm oracle-free docker volume rm oracle-data
Understanding Data Persistence: Your Data is Safe
One of the most common questions when working with Docker containers is: "What happens to my data?"
The good news is that your database is safer than you think.
What Deletes Your Data (and What Doesn't)
These actions are SAFE — your data persists:
- Stopping the container: docker stop oracle-free
- Removing the container: docker rm oracle-free
- Restarting your Mac
- Updating the container to a new version
Your data will ONLY be deleted if you explicitly run:
docker volume rm oracle-data
This is the only command that permanently destroys your database files. Docker will even warn you if the volume is still in use.
The Critical Rule: Always Attach Your Volume
Here's something crucial to understand: when you recreate a container (after running docker rm oracle-free), you must include the -v oracle-data:/opt/oracle/oradata flag in your docker run command.
Why? Here's the key distinction:
The volume persists automatically — it exists independently on your system.
The container does NOT remember it — containers are stateless.
Think of it like this: Your database files are stored in a safe deposit box (oracle-data volume) at the bank (Docker). When you create a new container, you need to explicitly give it the key (-v oracle-data:/opt/oracle/oradata) to access that box.
Example: Recreating Your Container (Updates, Restarts, or Recovery)
Whether you're updating to a newer image, recovering from an accidental deletion, or just want a fresh container, the process is the same. Your data persists through it all. Let's say you removed your container and want to start fresh:
Step 1: Pull the Latest Image (Optional but Recommended)
Before recreating your container, it's a good idea to check for updates:
docker pull container-registry.oracle.com/database/free:latest-lite
Example output when downloading a newer version:
If you already have the latest version, Docker will tell you:
⚡ Tip: Docker keeps old images even after pulling a new latest tag. If you want to clean up the old one, run:
docker image prune
Step 2: Create a New Container
# Create a new container with the SAME volume attached
docker run \
--name oracle-free \
-p 1521:1521 \
-e ORACLE_PWD=OracleIsAwesome \
-v oracle-data:/opt/oracle/oradata \
-d container-registry.oracle.com/database/free:latest-lite
🌩️ Note: The
-dflag runs the container in detached mode (in the background). Unlike the initialdocker runcommand in this guide, which attaches to your terminal and shows live logs, using-dstarts the container and immediately returns you to your command prompt. The container keeps running in the background, and you can view its logs anytime withdocker logs -f oracle-free.
What happens:
- Docker detects the existing oracle-data volume
- It reuses it (does NOT create a new one)
- Your database comes back exactly as you left it — all tables, users, and data intact
Important: Passwords Are Preserved
When you restore from an existing volume, the -e ORACLE_PWD flag is ignored. Your database already has passwords stored in the datafiles, so SYS and SYSTEM keep their original passwords. If you created a dev user, it still exists with its password unchanged.
The -e ORACLE_PWD flag only matters when starting with a fresh database (no volume or a new volume name).
Best Practice: Create a Dedicated Developer User
The goal of this guide is to move beyond a simple demo and set you up with a professional development environment that mirrors real-world best practices. To do this, we will address two fundamental principles: one for security and one for database health.
1. Security: The Principle of Least Privilege
First, you should never use the powerful SYSTEM or SYS accounts for everyday application development. Doing so is a security anti-pattern that violates the principle of least privilege. Our first step is to create a dedicated, less-privileged dev user specifically for our application.
2. Database Health: Separating User Data from System Data
Second, we must address a specific quirk of this "lite" container. To provide the quickest possible startup experience, it intentionally defaults to using its own critical SYSTEM tablespace for all user data. While this is fine for a temporary "Hello, World!" test, it is a major anti-pattern for building real applications. The SYSTEM tablespace is reserved for the database's core metadata; mixing your app's data with it can risk database stability and would never be allowed in a production environment.
To build our application on a proper foundation, we will override this default by creating a separate tablespace for our dev user. This ensures our local setup behaves like a real-world database, making our application more robust and portable.
The following steps show the complete, professional method for creating a new user that adheres to both of these best practices.
🌩️ These commands should be run as the
SYSuser. Connect using your the fulldocker execcommand.docker exec -it oracle-free sqlplus sys/OracleIsAwesome@localhost:1521/freepdb1 as sysdba
Step 1: Create a Dedicated Tablespace
Create a new tablespace named dev_data where your user's tables and data will be stored. This is a critical best practice for database health and management.
CREATE TABLESPACE dev_data DATAFILE '/opt/oracle/oradata/dev_data01.dbf' SIZE 100M AUTOEXTEND ON;
Step 2: Create the dev User
Now, create the dev user and assign your new tablespace as its default home right from the start.
CREATE USER dev IDENTIFIED BY DevPassword123 DEFAULT TABLESPACE dev_data;
🌩️ Note: Feel free to replace
DevPassword123with a secure password of your own. Just remember to update it in the shortcut scripts later!
Step 3: Grant Storage Quota
Allow the user to store data in their new dev_data tablespace.
ALTER USER dev QUOTA UNLIMITED ON dev_data;
Step 4: Grant Permissions
Finally, grant the user the rights to connect to the database (CONNECT) and create objects like tables and views (RESOURCE).
GRANT CONNECT, RESOURCE TO dev;
You can now type exit to leave the SQL*Plus session.
To connect as your new dev user, you can use the docker exec command again. Once connected, run the following quick test to confirm everything works as expected.
First, connect:
docker exec -it oracle-free sqlplus dev/DevPassword123@localhost:1521/freepdb1
Now, at the new SQL> prompt, test your schema:
-- Confirm your schema works
CREATE TABLE hello (msg VARCHAR2(50));
INSERT INTO hello VALUES ('Welcome to your dev schema');
SELECT * FROM hello;
After confirming it works, you can exit the session.
Note: To make switching between your
devuser and admin users easier, check out the bonus section at the end of this article for a helpful script you can add to your shell configuration.
Why 23ai Might Be the Only Database You Need
Oracle 23ai Free isn't just a traditional relational database. It integrates modern features that allow it to replace other specialized databases in your stack.
Better than Postgres?
Oracle 23ai includes all the robust, enterprise-grade relational features you expect (ACID transactions, advanced SQL, PL/SQL). But it also adds unique capabilities like AI Vector Search, allowing you to build powerful semantic search and RAG applications directly within the database.
Better than MongoDB?
Oracle's JSON Relational Duality Views are a revolutionary feature. They let you work with data as both structured relational tables and flexible JSON documents—simultaneously. The data is stored once, but can be accessed, modified, and queried from either perspective with full ACID compliance. This eliminates the object-relational mismatch and provides the flexibility of a document store with the power of a relational database.
This means your application doesn’t need complex mapping layers — your JSON and relational models stay in sync automatically.
| Capability | MongoDB | Oracle 23ai Free |
|---|---|---|
| Flexible JSON Storage | ✅ | ✅ |
| Transactional JSON | ❌ (Limited) | ✅ (Full ACID) |
| Combine JSON + Relational | ❌ | ✅ (JSON Duality Views) |
| Built-in AI Vector Search | ❌ | ✅ |
Conclusion
Running Oracle Database on a Mac is no longer a chore. With native ARM64 containers, it's fast, efficient, and incredibly easy to get started. You get a world-class, enterprise-grade database with cutting-edge AI and JSON features, all running locally on your machine for free.
Happy building! ☁️
Bonus: Faster Connections with Shell Shortcuts
As you work with Oracle, you'll find you sometimes need to perform administrative tasks as a privileged user, but you should use a dedicated dev user for daily work. To make this workflow seamless, you can create a set of shortcuts.
1. Create a Custom Script File
First, place the shortcut functions into a dedicated file. A common and safe practice is to use a hidden file in your home directory. Create and paste the following into a new file named ~/.zsh_oracle_shortcuts.
# Oracle DB connection shortcuts
# Connect as dev user using sqlplus inside the container
function sql-dev() {
docker exec -it oracle-free sqlplus dev/DevPassword123@localhost:1521/freepdb1
}
# Connect as dev user using local sqlcl client
function sqlcl-dev() {
# This requires you to have sqlcl installed locally (e.g., via Homebrew)
sql dev/DevPassword123@localhost:1521/freepdb1
}
# Connect as SYSTEM admin using sqlplus inside the container
function sql-system() {
docker exec -it oracle-free sqlplus system/OracleIsAwesome@localhost:1521/freepdb1
}
# Connect as SYS superuser using sqlplus inside the container
function sql-sys() {
docker exec -it oracle-free sqlplus sys/OracleIsAwesome@localhost:1521/freepdb1 as sysdba
}
2. Safely Load the Script in Your .zshrc
Now, add the following lines to the end of your ~/.zshrc file. This code safely checks if your shortcut file exists before trying to load it.
# Load Oracle DB shortcuts if the file exists
if [ -f "$HOME/.zsh_oracle_shortcuts" ]; then
source "$HOME/.zsh_oracle_shortcuts"
fi
3. Reload Your Shell
For the changes to take effect, either restart your terminal or run source ~/.zshrc.
4. Use Your New Shortcuts
You can now connect to your database instantly with these simple commands:
-
sql-dev: Connect as your developer user. -
sqlcl-dev: Connect as your developer user using the local sqlcl tool. -
sql-system: Connect as theSYSTEMadministrator. -
sql-sys: Connect as theSYSsuperuser.
Changing the Developer Password
If you need to change the dev user's password in the future, follow these three steps:
Connect as an Admin: Log in as
SYSTEMor SYS using one of your shortcuts (sql-systemorsql-sys).-
Alter the User: Run the ALTER USER command with your new password:
ALTER USER dev IDENTIFIED BY MyNewSecret123; Update Your Shortcuts: This is critical. Immediately edit your
~/.zsh_oracle_shortcutsfile and update the old password to the new one in both thesql-devandsqlcl-devfunctions. If you don't do this, your shortcuts will stop working.
Keeping Your Shortcuts Working After Container Restarts
Your shell shortcuts will continue working seamlessly after recreating the container, as long as:
- Container name matches:
--name oracle-free - Volume is attached:
-v oracle-data:/opt/oracle/oradata - Passwords are preserved (automatic when using the same volume)
If all three match, your shortcuts work immediately — no reconfiguration needed.
Cover Photo by BoliviaInteligente on Unsplash











Top comments (0)