A Linux development workstation should let you open a project, restore its dependencies, run tests and debug a failure without first repairing the machine. Installing an editor is only one part of that job. Package ownership, runtime versions, repository access and recovery arrangements matter just as much.
The most dependable approach is to build in layers: establish a working desktop, install a small set of host tools, isolate project dependencies, then verify the complete workflow. Keep the operating system responsible for the operating system. Let each project describe the tools and libraries it needs.
This guide covers that workstation foundation. Python environment management and container configuration have their own guides; here, the emphasis is on choosing where tools belong, connecting them properly and avoiding changes that make the next project harder to run.
Choose the Distribution Around Your Work
Start with the requirements of the projects you expect to develop. Check their contributor documentation, supported operating systems, compiler requirements and deployment targets. If your employer supports one distribution, using it can save more time than choosing a different desktop for its appearance.
Do not replace a working installation simply because another distribution has a reputation for developers. Instead, establish whether your current release receives security updates and whether the required tools have a supported installation route. Use the guide to choosing a Linux distribution if that decision is still open.
Matching the production distribution can be useful for software that depends closely on system libraries or packaging. It is not a substitute for testing in the actual deployment environment, though. Treat the workstation as a development host, not an accidental replica of a server that nobody has documented.
Check Hardware Before Customising the Desktop
As a planning suggestion rather than a published minimum, consider 16 GB of memory for general development and 32 GB if your intended workload includes several services, virtual machines or large builds. Existing machines with less memory can still be useful; choose the workflow before choosing an upgrade.
Budget storage for source repositories, dependencies, build output, container images and backups awaiting transfer. A nominally spacious drive can become cramped once several projects accumulate their own caches. Keep room for a clean rebuild rather than planning around the size of the source files alone.
Test the equipment you actually use: external monitors, the docking station, Wi-Fi, audio, suspend and resume. The Linux hardware compatibility checks are worth completing before filling the machine with development tools. A successful compiler installation does not make an unreliable dock less annoying.
Establish a Clean Operating System Baseline
Install available operating system updates and restart when required before adding repositories or language managers. Confirm that networking, the clock, display scaling and your normal login account work correctly. On a managed workstation, complete device enrolment and access requirements before changing security settings.
Use an ordinary user account for development and reserve administrative access for host maintenance. Create your project directories as that user. Avoid launching the editor or installing project dependencies with administrative privileges simply because an earlier operation returned a permission error.
Record the distribution release, processor architecture and installation choices in a short workstation note. Add storage encryption and recovery arrangements where applicable, but keep recovery secrets somewhere protected rather than in the note itself.
A fresh desktop installation should not be assumed to contain a complete development environment. Ubuntu’s developer installation documentation, for example, identifies developer tooling as a separate post-installation task. Make the baseline explicit instead of discovering missing components one failed build at a time.
Install a Small Host Toolset
Begin with tools that support several projects: Git, an SSH client, archive utilities, certificate support and the build tools your work requires. Add language runtimes afterwards. There is little value in installing every compiler available just in case you eventually become responsible for everything.
| Tool category | Typical choices | Install when |
|---|---|---|
| Version control | Git | You work with repositories or contribute changes |
| Remote access | OpenSSH client | You use SSH repository access or remote development hosts |
| Native compilation | GCC or Clang, with the required linker and headers | The project or one of its dependencies builds native code |
| Build coordination | Make, CMake or Ninja | The project’s build instructions require it |
| Debugging | GDB or LLDB | Your language and project use a native debugger |
| Network and archive utilities | curl, tar and unzip | Documented setup or diagnostic tasks require them |
Use the distribution’s package manager for this host foundation. Package names and package groups differ, so do not paste an installation sequence written for another distribution. The APT, DNF and Pacman guide covers those differences without mixing their instructions.
For C and C++ work on Ubuntu, the distribution provides separate GCC compiler packages: gcc for C and g++ for C++. Ubuntu’s GCC setup instructions provide the supported installation route. Select the project’s required compiler version rather than assuming the default compiler is always the right one.
After installation, verify more than the presence of an application launcher. Open an existing small project or an official tutorial project, complete its build and run a test. That checks the relationship between the compiler, headers, linker and build system, not just whether one program reports a version.
Decide Which Installer Owns Each Tool
Give every installed component a clear owner. The distribution package manager should normally own host utilities and system libraries. A project’s dependency manager should own its application libraries. A user runtime manager may own development runtimes when several versions are required.
A useful boundary is to ask how you would remove or update the component. If the answer involves guessing which installer created which files, simplify the arrangement before adding more tools.
Avoid installing several copies of the same editor or runtime without a reason. If a terminal opens one installation while the desktop launcher opens another, troubleshooting becomes needlessly confusing. Record deliberate exceptions, including their installation paths and update method.
Choose Desktop Packaging With Integration in Mind
A sandboxed application may need extra configuration to reach project directories, host tools or devices. Flatpak’s access model separates applications from host resources, with permissions and portals controlling access; the Flatpak sandbox permissions documentation describes those boundaries.
For an editor that must interact closely with host compilers, debuggers and container tools, choose its installation format deliberately. Do not grant access to the entire home directory as a reflexive fix for one inaccessible folder. Check whether the application’s supported integration method meets your needs first.
The broader guide to native packages, Flatpak and Snap covers application installation choices. For workstation setup, the immediate goal is consistency: one intended installation, a known update route and the access required for your work.
Give Projects a Predictable Home
Create one main development directory inside your home directory, then organise repositories by employer, client or purpose. Keep the arrangement simple enough that another person could recognise it without a tour.
Choose a filesystem location you control rather than placing source under system directories. The Linux filesystem directory guide explains the distinction between personal files, installed applications and system configuration.
Separate source code from disposable output. Build directories, downloaded dependencies and test artefacts should have recognisable locations so that cleaning a project does not become an exercise in identifying mysterious folders.
Do not run one working copy through several competing synchronisation systems. Use version control to exchange committed code and a backup process to protect local work. If you use a synchronised folder, establish how it handles concurrent changes before trusting it with an active repository.
Keep ownership predictable too. If files suddenly become unwritable, inspect the affected path and identify which process created them. Avoid granting everyone write access or changing ownership across broad directory trees. The file permissions and ownership guide provides the checks needed to repair the cause rather than hide it.
Configure Git Identity and Repository Access Separately
Set your Git author name and email before making your first commit. Review them again inside a work repository if you also use the machine for personal projects. Git supports both user-wide configuration and repository overrides, as documented in its first-time setup instructions.
Keep commit identity separate from authentication. The name attached to a commit is not the credential that grants access to a hosting account. Configure both, then verify them independently.
Choose an authentication method supported by your organisation. For SSH access, protect the private portion of the credential and upload only the public portion to the hosting service. A passphrase and an SSH agent can work together, allowing protected credentials without repeatedly entering the passphrase during normal use. GitHub’s SSH setup instructions cover that arrangement for GitHub accounts.
Before connecting to an unfamiliar SSH host, verify its identity using the service’s published information or your organisation’s approved records. Do not treat an unexpected identity change as a prompt to click through faster.
Finish with a disposable repository: clone it, make a harmless change, review the diff, commit and push to a test branch. Confirm the author details in the resulting commit. This is a better acceptance test than finding that the Git application opens successfully.
Connect the Editor to the Actual Toolchain
Choose the editor or IDE around the project’s workflow. Begin with the team’s documented configuration if one exists, especially where debugging, formatting or generated code depends on it. Avoid importing a large extension collection before establishing a working baseline.
Check the publisher’s supported Linux installation routes. Visual Studio Code, for example, offers official Debian, RPM and Snap packages through its Linux installation instructions. Use those instructions for the chosen format rather than combining repository setup from several unrelated tutorials.
Verify Execution, Not Just Editing
Open a project and select its intended interpreter, SDK or compiler. Then run the same test through the editor and through a separate terminal. Both should use the expected tools and project configuration.
If the results differ, inspect the executable paths and environment settings before reinstalling anything. Record where the editor runs its tools: on the host, inside a container or on a remote machine. A debugger running in one environment cannot be assumed to see files and services in another.
Use project formatting rules when available. Enable one formatter for each relevant file type, then check the resulting diff before enabling formatting on save. A workstation setup should not introduce a repository-wide style change by accident.
Treat Repository Automation as Executable Content
Do not automatically trust every downloaded repository. Visual Studio Code’s Restricted Mode restricts features that can execute workspace content, including tasks and debugging, but it is not a guarantee against malicious extensions. Review the Workspace Trust security boundaries before changing those controls.
Apply the same caution to development assistants and automated tools. Review requests to run commands, install dependencies or access credentials. Permission to read a project should not become unrestricted permission to change the workstation.
Make the Terminal Predictable Before Making It Decorative
Start with the distribution’s default shell unless your work requires another. Learn how its startup configuration is organised before adding runtime managers, prompt frameworks and automatic directory hooks.
Keep configuration changes small and documented. Add one tool, open a fresh terminal and verify the intended result. Check both a standalone terminal and the terminal inside the editor, especially after changing how runtimes are selected.
When a tool appears to be missing, inspect the executable search path and the installation location. When the wrong version appears, identify which installation is being selected. Adding another copy rarely makes that diagnosis easier.
Keep ordinary file handling and diagnostic skills close at hand. The essential Linux terminal commands guide covers the foundations without requiring a heavily customised shell. A prompt that displays six status indicators is optional; being able to identify the current directory is not.
Keep Language Runtimes Under Project Control
Before installing a runtime, read the repository’s setup instructions and version declarations. Check which versions are exercised by continuous integration. The newest available release is not automatically the version the project supports.
For each language, decide who owns runtime installation, how a project selects its version and how dependencies are restored. Write those decisions into the project documentation rather than leaving them in one developer’s shell history.
Python Projects
Use a separate environment for each Python project and keep application dependencies out of the distribution-managed interpreter. Select that environment explicitly in the editor, test runner and debugger. The guide to Python versions and virtual environments covers the installation and selection details.
Verify the interpreter path when a package seems installed but cannot be imported. Also record whether notebooks, background tasks and editor tools use the same environment. Treat the environment as something to recreate from project records, not as the only surviving copy of the dependency list.
JavaScript, Rust and Other Toolchains
For a JavaScript project, follow its declared Node.js version, package manager and dependency records. Avoid changing package managers during workstation setup unless the project maintainers intend that migration. Restore the existing workflow before improving it.
Rust projects using rustup can declare their toolchain in a rust-toolchain.toml file. Environment variables and other overrides can affect selection, so inspect the active toolchain when builds differ between directories. The rustup toolchain override rules define that selection order.
Use the same discipline for Java, Go, .NET and other stacks: identify the required SDK, establish its owner and confirm that the editor and terminal select it consistently. Keep runtime upgrades separate from unrelated operating system or application changes where practical.
Use Containers Where They Solve a Project Problem
Decide whether the project needs containers before installing a container engine. An application with several backing services may justify that setup; a small standalone utility may not. Follow the project’s supported engine and configuration rather than assuming interchangeable command names guarantee identical behaviour.
The Docker and Podman development guide covers container installation and operation. At workstation level, establish where images and persistent data live, which ports services expose and how files written through mounted directories remain usable by your account.
Review privileges before accepting convenience changes. Membership of the docker group grants root-level privileges when it provides access to the rootful Docker daemon. Consider a supported rootless arrangement where it meets the workload; Docker’s Linux post-installation guidance makes that privilege distinction explicit.
Keep database data separate from disposable images and build caches. Before using any cleanup feature, identify what it removes and whether local volumes contain work worth retaining.
Where a task calls for a separate operating system, a guest kernel or a different testing boundary, assess a virtual machine instead. The KVM and QEMU guide covers that option without turning the workstation setup into a full virtualisation project.
Control Local Services and Network Exposure
For a development service intended only for your browser or editor, choose a loopback-only listening address where the application supports it. Share access over the network only when a test requires it, and undo the change when that test ends.
Check the service’s listening address rather than relying on the fact that you opened it through localhost. Review container port publication separately. Use the Linux firewall guide for host firewall decisions, but do not treat a firewall as a replacement for sensible application settings.
Decide which services should start automatically. A database used every day may warrant that arrangement; a collection of abandoned experiments usually does not. Record the start, stop and data-location procedures for anything the project depends on.
For deliberately persistent services, use the systemd service management guide to distinguish user services from system services. Keep project experiments out of system-wide startup configuration unless there is a clear reason to put them there.
Protect Development Credentials From the Start
Use separate development credentials with only the permissions the task requires. Avoid placing production access on the workstation simply to make local testing easier. Follow your organisation’s approved storage and access process where one exists.
Keep real secrets out of committed configuration. Provide example configuration with placeholder values so that another developer can see what is required without receiving your credentials. An ignored local environment file may be a practical input method, but do not treat it as a protected vault.
Check more than source files before sharing a project or diagnostic bundle. Review logs, screenshots, database exports, shell history and editor configuration for credentials or private information. Build an agreed response process for exposed credentials, including revocation and replacement, using the OWASP secrets management guidance as a security reference.
On a portable workstation, include storage encryption, screen locking and protected recovery information in the setup plan. Keep credential recovery arrangements usable if the laptop itself is lost. Backing up the only recovery document onto the same laptop is an arrangement with a rather obvious flaw.
Tune Performance Only After Measuring a Real Workload
Establish a baseline before changing system settings. Open a representative project, restore its dependencies, run a clean build and execute the tests. Observe memory use, CPU activity and storage behaviour during those tasks.
Use the Linux resource monitoring guide to investigate the part of the workload that is actually slow. Separate a slow dependency download from a slow compiler run, and separate editor indexing from application execution.
Keep generated directories out of searches and indexing where the editor allows it and the project does not need them indexed. Adjust build parallelism to leave the desktop usable. If an application reports a resource limit, investigate its documented requirement before raising host-wide limits.
Do not begin by disabling security controls, applying arbitrary kernel settings or copying a performance configuration written for different hardware. Make one change at a time, rerun the same workload and retain the change only when it produces a useful result.
Document Updates, Backups and Recovery
Maintain a short record of installed development applications, added repositories, runtime managers and unusual configuration. Record installation methods as well as names. That record should help rebuild the workstation without preserving every cache and temporary file.
Keep security maintenance separate from major project migrations where possible. Schedule operating system release upgrades, runtime changes and large IDE updates so there is time to test and recover. The Linux security updates guide covers update management beyond the initial installation.
Define the backup scope explicitly. Include uncommitted work, local repositories, configuration and database exports that cannot be recreated from shared records. Exclude reproducible caches when appropriate, but confirm that they really are reproducible first.
Do not use a remote Git repository as the entire recovery plan. Check which files and local state it does not contain, then protect those through a separate process. Use the desktop backup and recovery guide to plan both backup storage and restoration.
Test recovery with a sample project in another directory or a spare environment. Confirm that you can recover the source, restore dependencies and run tests without relying on undocumented files from the original working copy.
Run an End-to-End Acceptance Test
Finish with a small project that resembles your normal workload. A successful installation screen is not enough. The workstation should support the complete edit, test, debug and commit cycle after a fresh login.
- Restore the project: Clone or recover it into a new directory and follow its written setup instructions.
- Verify tool selection: Confirm that the terminal, editor, test runner and debugger use the intended runtime or compiler.
- Exercise the workflow: Run tests, set a breakpoint, make a small change and review the resulting diff.
- Check access and exposure: Push a test branch, inspect required local services and verify that no unnecessary network access was enabled.
- Repeat after restarting: Confirm that authentication, environment selection and required services still behave as documented.
For a hypothetical web API project, that could mean restoring dependencies into its project environment, starting a disposable local database, running migrations against test data, executing the test suite and debugging one request. Use synthetic data and development credentials throughout.
Record any manual fix the acceptance test reveals. If a fresh terminal needs an undocumented step, or a build works only inside one editor session, the setup is not finished. Resolve that dependency while it is visible.
Stop adding tools once the workstation passes this test. A useful development machine is not the one with the longest software list. It is the one you can maintain, reproduce and trust to run the next project without a preliminary repair session.