nidaqmx: driving National Instruments data acquisition hardware from Python
NI-DAQmx API for Python, created and supported by NI
At a glance
- What is it?
- The nidaqmx package is National Instruments' own Python binding for the NI-DAQmx driver, implemented as an object-oriented ctypes wrapper over the C API, with task and virtual channel abstractions that mirror the driver's own model. It requires the NI-DAQmx driver and at least one DAQ device to do anything.
- Who is it for?
- Adopt nidaqmx if you are writing acquisition or control software for NI data acquisition devices and want the vendor-supported Python binding rather than a third-party one. Do not adopt it if you need hardware-independent acquisition code, since it is tied to NI hardware and to the NI-DAQmx driver installation.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A ctypes wrapper, not a native extension
The implementation section of the project documentation is one sentence and it defines the shape of the whole package: it is implemented in Python as an object-oriented wrapper around the NI-DAQmx C API using the ctypes Python library.
That is a deliberate choice with consequences in both directions. ctypes calls into the driver's shared library at runtime through the platform's dynamic linking, so there is no compiled extension module to build for your Python version, no ABI tag to match, and no compiler in the install path. The package installs like any pure Python distribution.
The cost of that approach is that the C API is exposed to Python as-is, and the object-oriented layer on top has to do the work of making it usable. That layer is what the rest of the API is.
The provenance is unusually clear. The documentation's header table names National Instruments as the author, and the repository description says the NI-DAQmx API for Python is created and supported by NI. The package is the official one, not a third-party wrapper, and the maintainers listed in the project metadata are NI staff.
The licence field on the repository shows a custom licence that GitHub cannot classify, while the project metadata declares MIT in both the license field and the classifier. That discrepancy is worth resolving by reading the LICENSE file before you vendor it, though the practical difference for most users is nil because the package is normally installed from PyPI rather than redistributed.
The documentation points to the NI-DAQmx User Manual for an overview of NI-DAQmx, key concepts and measurement fundamentals, and notes that the NI-DAQmx Help also installs locally with the full version of NI-DAQmx.
Tasks and virtual channels, and why the API mirrors the driver
The key concepts section of the documentation explains the model, and the model is the driver's, not the binding's.
A task is a collection of one or more virtual channels with timing, triggering and other properties. Creating one is the first thing most programs do.
>>> import nidaqmx
>>> with nidaqmx.Task() as task:
... passVirtual channels, sometimes referred to generically as channels, are software entities that encapsulate the physical channel along with other channel specific information, such as range, terminal configuration and custom scaling, that formats the data. A physical channel is a terminal or pin at which you can measure or generate an analog or digital signal, and a single physical channel can include more than one terminal, as in the case of a differential analog input channel or a digital port of eight lines.
Every physical channel on a device has a unique name following the NI-DAQmx physical channel naming convention, for instance cDAQ1Mod4/ai0, Dev2/ao5 and Dev6/ctr3.
The real work happens when you add a channel to a task and read from it, where the range configuration is part of the channel definition.
>>> import nidaqmx
>>> with nidaqmx.Task() as task:
... task.ai_channels.add_ai_voltage_chan("Dev1/ai0", min_val=-10.0, max_val=10.0)
... task.read()
...
AIChannel(name=Dev1/ai0)
-0.149The result of that read is a single value, -0.149, which is a voltage in the configured range. Note the shape of the API: the channel name and its range are declared on the task, and reading is a method on the task, not a separate handle. The with statement does the resource management, so the task is closed when the block ends.
Installing the package and the driver
There are two separate installations, and people routinely conflate them. The package is one; the driver is the other.
The package comes from PyPI.
$ python -m pip install nidaqmxIf you want the gRPC path, the package needs its extra.
$ python -m pip install nidaqmx[grpc]The driver is the piece that actually talks to hardware, and the package ships a command line interface to streamline installing it.
$ python -m nidaqmx installdriverOn Windows this command downloads and launches an online streaming installer from ni.com. On Linux it downloads the repository registration package for your distribution and installs the driver using your package manager. Running nidaqmx requires NI-DAQmx to be installed, which is why this step exists at all.
There is also a manual route. Visit ni.com/downloads to get the latest version of NI-DAQmx. The documentation makes a useful point about the optional extras: none of the recommended additional items are required for nidaqmx to function and they can be removed to minimize installation size, but it is recommended to continue installing the NI Certificates package so that the operating system trusts NI built binaries.
The project also ships a console script, nidaqmx, mapped to nidaqmx.__main__:main, and the .env.sample file in the repository root documents one runtime switch worth knowing about. On Windows, nidaqmx-python uses the UTF-8 version of the NI-DAQmx C library, nicai_utf8, by default, falling back to the MBCS version, nicaiu, if that is not available, and the NIDAQMX_C_LIBRARY environment variable overrides the choice.
What you need before any code runs
There is a hard prerequisite that is easy to overlook in a tutorial, and it is stated plainly in the Getting Started section: in order to use the nidaqmx package, you must have at least one DAQ device installed on your system. Both physical and simulated devices are supported.
The examples in the documentation use an X Series DAQ device, for example a PXIe-6363, PCIe-6363 or USB-6363. NI MAX or the NI Hardware Configuration Utility can be used to verify and configure devices, and the documentation includes screenshots from both tools showing where the device name is found. That device name, Dev1/ai0 in the example above, is exactly the string your code uses, so getting it right in the configuration utility is step one of any real project.
The support matrix is broad and worth reading before you plan. The package supports all versions of NI-DAQmx, although some functions in the package may be unavailable with earlier versions of the driver. It supports Windows and Linux operating systems where the NI-DAQmx driver is supported, with a pointer to the NI hardware and operating system compatibility page for which driver versions support which hardware on which operating system.
On the Python side, CPython 3.9 and later is supported, and the project metadata lists classifiers through Python 3.14 with requires-python set to 3.9 and above but below 4.0. PyPy3 is supported for non-gRPC use cases, with the gRPC status on PyPy tracked as an upstream issue.
One thing the documentation flags about version matching: newer examples may demonstrate features that are not available in older versions of nidaqmx, which is why the examples directory in the repository is versioned and the documentation tells you to check out the examples directory in the tag matching your version.
Running the examples without installing a world of dependencies
The examples directory is substantial and organised by acquisition type, which tells you what the package is expected to do. There are analog_in, analog_out, digital_in, digital_out, counter_in and counter_out directories, plus a synchronization directory. Alongside them sit standalone scripts for specific behaviours: channel_properties.py for inspecting what a channel reports about itself, every_n_samples_event.py for the hardware-timed event every N samples pattern, playrec.py for the playback and recording loop, pwr_hw_timed.py and pwr_sw_timed.py for hardware versus software timed power measurements, pwr_hw_timed_stream.py for the streaming variant, system_properties.py for querying the system, and nidaqmx_warnings.py which demonstrates the warning types the package raises.
The workflow advice is practical. You can use tools such as pipx or uv to automatically install the required dependencies for an nidaqmx example program and run it, with pipx run voltage_sample.py or uv run voltage_sample.py given as the examples.
That is a genuinely useful pattern for this kind of package. An example that needs a driver, a device and a set of Python dependencies is otherwise a chore to run, and the pipx and uv one-shot invocations remove the environment setup entirely. The caveat is the same one the documentation states about versions: check out the examples directory in the tag matching the nidaqmx version you are using, so the example does not call a function that does not exist in your driver.
What the binding does not do for you
Two limits are structural and worth naming before you commit.
The first is that this is a binding to one vendor's driver and one vendor's hardware. The abstraction, tasks and virtual channels, is genuinely well designed, but it is a model of a DAQ system, and it is NI's model of a DAQ system. A codebase that needs to drive hardware from more than one vendor, or to run against a simulator for one vendor and real hardware for another, ends up with an abstraction layer of its own on top, and the value of using the vendor binding directly shrinks. The simulator support does help with testing, and the package supports CPython and PyPy on both Windows and POSIX, but the driver installation is still a hard requirement for anything real.
The second is the dependency on the driver's own lifecycle. Because the binding is ctypes over the C API, the driver installation, its version, and its platform support are all part of your operational surface. The documentation is explicit that some functions may be unavailable with earlier driver versions, so the effective API of a given nidaqmx release depends on which driver you have installed. That is a version matrix you have to manage, and it is the usual reason a project like this pins both the package and the driver.
On the maintenance side, the repository is not archived, the last push was on 2026-10-19, and the recent releases are 1.6.0 on 2026-08-07, 1.5.0 on 2026-04-23 and 1.4.1 on 2026-02-16. The project metadata carries the version 1.7.0.dev0, which is the development version in the tree, and it is a stable classifier, Development Status :: 5 - Production/Stable, from a vendor with a commercial interest in the package working.
The alternative to weigh against is writing against the C API yourself, which is what the binding does. For most instrument control applications the binding is the reason to use Python at all here, so the practical comparison is against a different language binding or a different vendor's SDK, and in both cases the deciding factor is which hardware you actually own.
Editorial conclusion
Adopt nidaqmx if you are writing acquisition or control software for NI data acquisition devices and want the vendor-supported Python binding rather than a third-party one. Do not adopt it if you need hardware-independent acquisition code, since it is tied to NI hardware and to the NI-DAQmx driver installation. Before you start, install the driver with python -m nidaqmx installdriver and confirm your device appears in NI MAX, and note the last push was on 2026-10-19 with release 1.6.0 on 2026-08-07.
Frequently asked questions
How do I install nidaqmx and the NI-DAQmx driver?
Install the package with python -m pip install nidaqmx, or with the grpc extra for the gRPC path. The driver is separate and can be installed with python -m nidaqmx installdriver, which on Windows launches an online installer from ni.com and on Linux installs the repository registration package through your package manager.
What do tasks and virtual channels mean in nidaqmx?
A task is a collection of one or more virtual channels with timing, triggering and other properties. A virtual channel encapsulates the physical channel together with channel specific information such as range, terminal configuration and custom scaling, and every physical channel has a unique name following the NI-DAQmx naming convention.
Which Python versions and operating systems does nidaqmx support?
CPython 3.9 and later is supported, with classifiers listed through Python 3.14, and PyPy3 is supported for non-gRPC use cases. The operating systems supported are Windows and Linux, in the places where the NI-DAQmx driver itself is supported.
Do I need real hardware to try nidaqmx?
You need at least one DAQ device installed on your system, but both physical and simulated devices are supported, so a simulated device is enough to get started. NI MAX or the NI Hardware Configuration Utility can be used to verify and configure devices.
How do I run the nidaqmx example programs?
The examples are in the examples directory of the repository, and you can use pipx or uv to install the required dependencies and run an example in one step, for example pipx run voltage_sample.py or uv run voltage_sample.py. Use the examples from the tag matching your nidaqmx version, since newer examples may use features unavailable in older versions.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ni-nidaqmx-python)Was this useful?