Tossing pip and conda into the same setup without a plan is basically asking for a weekend spent untangling dependency hell and broken imports. If you set up clean project boundaries from day one, you dodge those painful solver loops altogether. Here are the core commands I rely on to keep things smooth and completely stable.

- Create new environment:
conda create --name myenv python=3.10 - Activate environment:
conda activate myenv - List all environments:
conda env list - Export for teams:
conda env export --from-history > env.yml - Remove environment:
conda env remove --name myenv
The Golden Rule: Leave Your Base Environment Alone
Think of your base environment as the control room for conda itself, not a playground for random libraries. Shoving everyday project packages into base is begging for trouble. The more third-party stuff you drop in there, the higher the chance you break the package manager's internal plumbing.
Get in the habit of spinning up a fresh environment for every single project you touch. If base gets corrupted, your only real way out is nuking the whole conda installation and starting over. Keeping base untouched means you always have a rock-solid safety net when things go sideways.
How to Set Up a Conda Environment Properly
Spinning up a fresh workspace takes about ten seconds. At its simplest, you just tell conda to make a new container and give it a sensible name. Running conda create --name data_project sets aside an isolated folder, ready to take whatever libraries you throw at it.
Pinning Your Python Version and Leaning on conda-forge
You almost never want a generic blank workspace, though. It’s way better to lock down the exact Python interpreter your code needs right at the jump. Running conda create --name data_project python=3.11 makes sure you're coding against the specific runtime you intended.
For actual package downloads, stick to the conda-forge community channel whenever you can. Conda's default channel often lags behind new releases and patches. Adding -c conda-forge right into your creation command gives you access to modern, actively maintained versions of your dependencies.
Keeping Environments Local with the --prefix Flag
Sometimes you want an environment sitting right inside your project directory rather than buried in your user home folder. This makes life effortless when you finish a project and want zero lingering clutter on your drive.
Just run conda create --prefix ./env pandas numpy to build everything right there in the working folder. You activate it by pointing straight at that relative path instead of a global name. It keeps heavy data science or machine learning builds self-contained, and cleaning house is as easy as tossing the repo in the trash.
Moving Around: Activating, Checking, and Stepping Out
Before you can run any code inside your environment, you need to step into it. Fire up your terminal and run conda activate data_project; you'll see the environment name pop up in your prompt, confirming you're working inside your isolated sandbox.

Whenever you need a sanity check on what's installed in your current space, run conda list. It prints every library along with its exact build and version. If you want a bird's-eye view of every workspace sitting on your drive, listing conda environments takes just a single command. Once you're done for the day, running conda deactivate drops you right back into your base terminal.
Handling Dependencies: Getting Conda and Pip to Coexist
People often think they have to pick a side between pip and conda, but they actually complement each other well if you respect a simple boundary. If you mix them carelessly without an order of operations, neither tool has visibility into the other's changes, and things fall apart fast.
Rule #1: Conda Takes Care of Business First, Pip Wraps Up
If you only remember one piece of advice from this entire guide, make it this: install everything you can through conda before you ever touch pip. Conda relies on a full SAT solver that calculates cross-package compatibility across all dependencies before touching your disk.
Only pull in pip for obscure or brand-new packages that genuinely don't exist on conda channels yet. And once you pull the trigger on pip in an environment, stop running conda install commands on it. Conda cannot reliably track the extra baggage pip brings along, and forcing it to install more stuff afterward will scramble your setup. The same logic holds if you need to upgrade pip inside that environment: wait until all your conda packages are locked in place.
Bumping Package Versions Without Breaking Things
Updating a library shouldn't mean tearing down your whole workflow. When you just need a fresher release of a package you already use, run conda update scipy. Conda's solver figures out the path of least resistance so you get the update without throwing other libraries out of alignment.
Exporting and Sharing Your Workspace
The moment you hand code off to a teammate or a deployment target, you need a way to pass along the exact room you built it in. Exporting your workspace dumps a straightforward YAML file that serves as a clean recipe for anyone else.
Working with Mixed Operating Systems: Why --from-history Matters
A vanilla environment export captures hyper-specific operating system binaries. If you generate that dump on a Mac and hand it to a teammate running Windows, their installer is going to choke almost immediately.
This is why you should always use conda env export --from-history > environment.yml when collaborating across different platforms. It strips out low-level OS dependencies and only exports the top-level packages you explicitly asked conda to install. It’s easily the most reliable way to share environments across platforms without tears.
Exact Machine Clones: Using the --no-builds Flag
When everyone on the team is using identical hardware and operating systems, you can aim for tighter parity. Running conda env export --no-builds > environment.yml leaves out machine-specific build hashes while locking down explicit version numbers. It's ideal for matching your local dev environment to a matching Linux staging server.
Building and Duplicating Environments from Recipes
When a colleague hands you an environment YAML file, getting up and running is straightforward. Just run conda env create -f environment.yml, grab a coffee, and let conda fetch and configure every piece.
If you ever want to test a major library upgrade without risking a setup you know already works, clone it first. Running conda create --name test_env --clone original_env spins up an identical copy in moments. You can test your risky updates in the copy and keep your main workspace safe.
When conda env create -f environment.yml errors out: Nine times out of ten, it's hunting for a specific package build that isn't on the remote channel anymore. Try regenerating the file with --no-builds, or crack open the YAML and drop strict version pins for the troublesome library so conda can find an agreeable sibling version. Also, removing old environments before you attempt a fresh build from YAML ensures no leftover cache files confuse the solver.
Taking Environments Air-Gapped with conda-pack
Every now and then, you have to push code onto an air-gapped server or secure internal box that has zero internet connectivity. Standard YAML files won't help you there because they require an active connection to download the packages.
This is where conda-pack shines. It packs your entire operational environment, binaries and all, into a clean, portable tarball archive.
Bash
# Install conda-pack first
conda install -c conda-forge conda-pack
# Pack the active environment
conda pack -n myenv -o myenv.tar.gz
# On the offline machine: extract and activate
mkdir -p /opt/myenv && tar -xzf myenv.tar.gz -C /opt/myenv
source /opt/myenv/bin/activate
conda-unpackYou just sling the archive over via USB or secure file drop, uncompress it on the target machine, run the unpack script, and you're good. No network calls needed.
Fixing Slow Resolve Times with Mamba and libmamba
Watching conda's default solver spin its wheels for twenty minutes on complex dependency trees gets old fast. You don't have to put up with that sluggishness anymore.
You can swap out the default engine for libmamba, a C++ rewrite of the solver that speeds up resolving by an order of magnitude.
Bash
# Enable the libmamba solver (conda 22.11+)
conda install -n base -c conda-forge conda-libmamba-solver
conda config --set solver libmambaIf you prefer an even faster direct replacement, grab the standalone Mamba CLI. It accepts the exact same syntax and command structure as conda, just tuned for speed.
Bash
conda install -n base -c conda-forge mambaFrom there on out, mamba create, mamba install, and mamba env export run just like their conda equivalents, except they finish in seconds instead of minutes.
Anaconda vs. Miniconda: The Practical Choice
Grabbing the full Anaconda bundle downloads gigabytes of pre-baked scientific tools and desktop apps you’ll probably never even touch. It hogs storage and clutters your path from day one.
Miniconda is what almost every experienced developer actually runs. It gives you the leanest possible foundation: just Python, conda, and basic system utilities. You start with a blank slate and pull in only the packages your current project actually needs, keeping your machine fast and clean.
Stick to Miniconda, create a fresh named workspace for every repo, use --from-history whenever you share an export with teammates on other operating systems, and switch to libmamba the moment your dependency trees get heavy. That simple playbook will keep your Python setup humming without the usual headaches.