diff --git a/nccompress/nc2nc.py b/nccompress/nc2nc.py
index 814bd83..2831ebd 100755
--- a/nccompress/nc2nc.py
+++ b/nccompress/nc2nc.py
@@ -164,7 +164,7 @@ def chunk_shape_nD(varShape, valSize=4, chunkSize=4096, minDim=1):
 
 
 def nc2nc(filename_o, filename_d, zlib=True, complevel=5, shuffle=True, fletcher32=False,
-    clobber=False, verbose=False, classic=True, lsd_dict=None, vars=None, buffersize=51200, mindim=1,ignoreformat=False):
+    clobber=False, verbose=False, classic=True, lsd_dict=None, vars=None, chunksize=4, buffersize=50, mindim=1,ignoreformat=False):
     """convert a netcdf file (filename_o) to another netcdf file (filename_d)
     The default format is 'NETCDF4_classic', but can be set to NETCDF4 if classic=False.
     If the lsd_dict is not None, variable names corresponding to the keys of the dict
@@ -197,8 +197,10 @@ def nc2nc(filename_o, filename_d, zlib=True, complevel=5, shuffle=True, fletcher
         ncfile_d = Dataset(filename_d,'w',clobber=clobber,format='NETCDF4')
     mval = 1.e30 # missing value if unpackshort=True
 
-    # Copy buffer specified in MB, so convert to bytes
-    buffersize = 1000000*buffersize
+    # Copy buffer specified in MiB, so convert to bytes
+    buffersize = buffersize*(1024**2)
+    # Chunk size specified in KiB, so convert to bytes
+    chunksize = chunksize*1024
 
     # create dimensions. Check for unlimited dim.
     unlimdimname = False
@@ -257,7 +259,7 @@ def nc2nc(filename_o, filename_d, zlib=True, complevel=5, shuffle=True, fletcher
         # check we have a mapping from the type to a number of bytes
         if ncvar.dtype.char in dtypes: 
             if verbose: sys.stdout.write('Variable shape: %s\n' % str(ncvar.shape))
-            if (ncvar.shape != ()): chunksizes=chunk_shape_nD(ncvar.shape,valSize=dtypes[ncvar.dtype.char],minDim=mindim)
+            if (ncvar.shape != ()): chunksizes=chunk_shape_nD(ncvar.shape,valSize=dtypes[ncvar.dtype.char],minDim=mindim,chunkSize=chunksize)
             if verbose: sys.stdout.write('Chunk sizes: %s\n' % str(chunksizes))
         else:
             sys.stderr.write("This datatype not supported: dtype : %s\n" % ncvar.dtype.char)
@@ -339,7 +341,8 @@ def parse_args(arglist):
     parser = argparse.ArgumentParser(description="Make a copy of a netCDF file with automatic chunk sizing")
     parser.add_argument("-d","--dlevel", help="Set deflate level. Valid values 0-9 (default=5)", type=int, default=5, choices=range(0,10), metavar='{1-9}')
     parser.add_argument("-m","--mindim", help="Minimum dimension of chunk. Valid values 1-dimsize", type=positive_int, default=1)
-    parser.add_argument("-b","--buffersize", help="Set size of copy buffer in MB (default=50)", type=int, default=50)
+    parser.add_argument("-s","--chunksize", help="Set chunksize - total size of one chunk in KiB (default=64)", type=int, default=64)
+    parser.add_argument("-b","--buffersize", help="Set size of copy buffer in MiB (default=500)", type=int, default=500)
     parser.add_argument("-n","--noshuffle", help="Don't shuffle on deflation (default is to shuffle)", action='store_true')
     parser.add_argument("-v","--verbose", help="Verbose output", action='store_true')
     parser.add_argument("-c","--classic", help="use NETCDF4_CLASSIC output instead of NETCDF4 (default true)", action='store_false')
@@ -363,7 +366,7 @@ def main(args):
     # copy the data from origin to destination
     nc2nc(args.origin, args.destination, zlib=zlib, complevel=args.dlevel, shuffle=not args.noshuffle,
         fletcher32=args.fletcher32, clobber=args.overwrite, lsd_dict=args.quantize,
-        verbose=verbose, vars=args.vars, classic=args.classic, buffersize=args.buffersize, ignoreformat=args.ignoreformat)
+        verbose=verbose, vars=args.vars, classic=args.classic, chunksize=args.chunksize, buffersize=args.buffersize, ignoreformat=args.ignoreformat)
                 
 def main_parse_args(arglist):
     """
diff --git a/nccompress/nccompress.py b/nccompress/nccompress.py
index c0e1cff..33376d0 100755
--- a/nccompress/nccompress.py
+++ b/nccompress/nccompress.py
@@ -98,7 +98,7 @@ def are_equal(infile,outfile,verbose):
         return False
     return True
 
-def nc2nc_cmd(infile,outfile,level,shuffle,verbose,buffersize,timing):
+def nc2nc_cmd(infile,outfile,level,shuffle,verbose,chunksize,buffersize,timing):
 
     cmd = []
     if timing:
@@ -112,6 +112,10 @@ def nc2nc_cmd(infile,outfile,level,shuffle,verbose,buffersize,timing):
     cmd.extend([nc2nc,'-d',str(level)])
     if (not shuffle): cmd.append('-n')
     # if verbose: cmd.append('-v')
+    if chunksize:
+        cmd.append('-s')
+        # All command line options have to be a string
+        cmd.append(str(chunksize))
     if buffersize:
         cmd.append('-b')
         # All command line options have to be a string
@@ -163,7 +167,7 @@ def check_and_overwrite(state,verbose,maxcompress):
         else:
             state['error'] = False
 
-def run_compress(infile,outfile,level=5,shuffle=True,verbose=False,buffersize=50,paranoid=False,
+def run_compress(infile,outfile,level=5,shuffle=True,verbose=False,chunksize=64,buffersize=500,paranoid=False,
                  overwrite=False,nccopy=False,maxcompress=10,timing=False):
 
     # Initialise state container
@@ -201,7 +205,7 @@ def run_compress(infile,outfile,level=5,shuffle=True,verbose=False,buffersize=50
     if nccopy:
         cmd = nccopy_cmd(infile,outfile,level,shuffle,verbose,buffersize,timing)
     else:
-        cmd = nc2nc_cmd(infile,outfile,level,shuffle,verbose,buffersize,timing)
+        cmd = nc2nc_cmd(infile,outfile,level,shuffle,verbose,chunksize,buffersize,timing)
 
     output = ''
     if verbose: print (' '.join(cmd))
@@ -227,7 +231,8 @@ def log_result(result):
     global result_list
     result_list.append(result)
 
-def compress_files(path,files,tmpdir,overwrite,maxcompress,level,shuffle,force,clean,verbose,buffersize,nccopy,paranoid,numproc,timing):
+def compress_files(path, files, tmpdir, overwrite, maxcompress, level, shuffle, force, clean, 
+                   verbose, chunksize, buffersize, nccopy, paranoid, numproc, timing):
 
     total_size_new = 0
     total_size_old = 0
@@ -287,7 +292,7 @@ def compress_files(path,files,tmpdir,overwrite,maxcompress,level,shuffle,force,c
                 continue
 
         # Try compressing the data
-        pool.apply_async(run_compress, args=(infile,outfile,level,shuffle,verbose,buffersize,paranoid,overwrite,nccopy,maxcompress,timing), callback=log_result)
+        pool.apply_async(run_compress, args=(infile,outfile,level,shuffle,verbose,chunksize,buffersize,paranoid,overwrite,nccopy,maxcompress,timing), callback=log_result)
 
     pool.close()
     pool.join()
@@ -358,7 +363,8 @@ def parse_args(arglist):
     parser.add_argument("-d","--dlevel", help="Set deflate level. Valid values 0-9 (default=5)", type=int, default=5, choices=range(0,10), metavar='{1-9}')
     # parser.add_argument("-l","--limited", help="Change unlimited dimension to fixed size (default is to not squash unlimited)", action='store_true')
     parser.add_argument("-n","--noshuffle", help="Don't shuffle on deflation (default is to shuffle)", action='store_true')
-    parser.add_argument("-b","--buffersize", help="Set size of copy buffer in MB (default=50)", type=int, default=50)
+    parser.add_argument("-s","--chunksize", help="Set chunksize - total size of one chunk in KiB (default=64)", type=int, default=64)
+    parser.add_argument("-b","--buffersize", help="Set size of copy buffer in MB (default=500)", type=int, default=500)
     parser.add_argument("-t","--tmpdir", help="Specify temporary directory to save compressed files", default='tmp.nc_compress')
     parser.add_argument("-v","--verbose", help="Verbose output", action='store_true')
     parser.add_argument("-r","--recursive", help="Recursively descend directories compressing all netCDF files (default False)", action='store_true')
@@ -377,8 +383,6 @@ def parse_args(arglist):
 
 def main(args):
     
-    verbose=args.verbose
-
     # We won't make users specify parallel if they've specified a number of processors
     if args.numproc: args.parallel = True
 
@@ -413,7 +417,22 @@ def main(args):
                     break
                 else:
                     # Compress all the files in this directory
-                    compress_files(root,files,args.tmpdir,args.overwrite,args.maxcompress,args.dlevel,not args.noshuffle,args.force,args.clean,verbose,args.buffersize,args.nccopy,args.paranoid,numproc,args.timing)
+                    compress_files(root,
+                                   files,
+                                   args.tmpdir,
+                                   args.overwrite,
+                                   args.maxcompress,
+                                   args.dlevel,
+                                   not args.noshuffle,
+                                   args.force,
+                                   args.clean,
+                                   args.verbose,
+                                   args.chunksize,
+                                   args.buffersize,
+                                   args.nccopy,
+                                   args.paranoid,
+                                   numproc,
+                                   args.timing)
                     # Note we've traversed this directory but set directory to an empty list
                     filedict[root] = []
         else:
@@ -427,7 +446,22 @@ def main(args):
     # are named the same, just in a separate temporary sub directory.
     for directory in filedict:
         if len(filedict[directory]) == 0: continue
-        compress_files(directory,filedict[directory],args.tmpdir,args.overwrite,args.maxcompress,args.dlevel,not args.noshuffle,args.force,args.clean,verbose,args.buffersize,args.nccopy,args.paranoid,numproc,args.timing)
+        compress_files(directory,
+                       filedict[directory],
+                       args.tmpdir,
+                       args.overwrite,
+                       args.maxcompress,
+                       args.dlevel,
+                       not args.noshuffle,
+                       args.force,
+                       args.clean,
+                       args.verbose,
+                       args.chunksize,
+                       args.buffersize,
+                       args.nccopy,
+                       args.paranoid,
+                       numproc,
+                       args.timing)
 
                 
 def main_parse_args(arglist):

Option to alter chunk size
Currently chunk size is hard coded to 4096 bytes (4K). This is too small for efficient operation and makes optimal chunk size calculations difficult.

https://github.com/aidanheerdegen/nccompress/blob/master/nc2nc#L258
diff --git a/test/test_nc2nc.py b/test/test_nc2nc.py
index 2f0505a..950be74 100644
--- a/test/test_nc2nc.py
+++ b/test/test_nc2nc.py
@@ -108,3 +108,10 @@ def test_nc2nc():
         pass
 
     nc2nc.nc2nc(ncfiles[0]+'2nc.nc4',ncfiles[0]+'2nc.2.nc4',clobber=True,classic=False,ignoreformat=True)
+
+    # Should make chunksize the same size as the variable
+    nc2nc.nc2nc(ncfiles[0], ncfiles[0]+'2nc.enormachunk.nc', clobber=True, chunksize=400)
+
+    ds = Dataset(ncfiles[0]+'2nc.enormachunk.nc')
+    data = ds.variables['data']
+    assert list(data.shape) == data.chunking()
\ No newline at end of file
diff --git a/test/utils.py b/test/utils.py
index 5d5d2e8..0b79598 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -22,7 +22,7 @@ def which(program):
     return None
 
 def remove_ncfiles(verbose=True):
-    for file in glob("*.nc"):
+    for file in glob("*.nc") + glob("*.nc4"):
         if (verbose): print("Removing {}".format(file))
         os.remove(file)
 

conda/dev-environment.yml
pip install -e .[dev]
parse_log_pytest
environment.yml
pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
certifi==2025.1.31
cftime @ file:///home/conda/feedstock_root/build_artifacts/cftime_1649636863755/work
charset-normalizer==3.4.1
commonmark==0.9.1
docutils==0.21.2
exceptiongroup==1.2.2
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
MarkupSafe==3.0.2
-e git+https://github.com/coecms/nccompress.git@ecb99719f000ee7802587a000eb875c0077ef459#egg=nccompress
netCDF4 @ file:///home/conda/feedstock_root/build_artifacts/netcdf4_1636302994507/work
numpy @ file:///home/conda/feedstock_root/build_artifacts/numpy_1651020388495/work
packaging==24.2
pbr @ file:///home/conda/feedstock_root/build_artifacts/pbr_1740384424725/work
pluggy==1.5.0
Pygments==2.19.1
pytest==8.3.5
recommonmark==0.7.1
requests==2.32.3
six @ file:///home/conda/feedstock_root/build_artifacts/six_1733380938961/work
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.2.1
urllib3==2.3.0
zipp==3.21.0

name: nccompress
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - bzip2=1.0.8=h7f98852_4
  - c-ares=1.18.1=h7f98852_0
  - ca-certificates=2025.2.25=h06a4308_0
  - cdo=2.0.3=he19d259_1
  - cftime=1.6.0=py39hd257fcd_1
  - curl=7.82.0=h7f8727e_0
  - eccodes=2.26.0=hc08acdf_0
  - expat=2.4.8=h27087fc_0
  - fftw=3.3.10=nompi_h77c792f_102
  - freeglut=3.2.2=h9c3ff4c_1
  - hdf4=4.2.15=h10796ff_3
  - hdf5=1.12.1=nompi_h2750804_100
  - icu=68.2=h9c3ff4c_0
  - jasper=2.0.33=ha77e612_0
  - jbig=2.1=h7f98852_2003
  - jpeg=9e=h166bdaf_1
  - keyutils=1.6.1=h166bdaf_0
  - krb5=1.19.3=h3790be6_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - lerc=2.2.1=h9c3ff4c_0
  - libaec=1.0.6=h9c3ff4c_0
  - libblas=3.9.0=16_linux64_openblas
  - libcblas=3.9.0=16_linux64_openblas
  - libcurl=7.82.0=h0b77cf5_0
  - libdeflate=1.7=h7f98852_5
  - libedit=3.1.20191231=he28a2e2_2
  - libev=4.33=h516909a_1
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgfortran-ng=13.2.0=h69a702a_0
  - libgfortran5=13.2.0=ha4646dd_0
  - libglu=9.0.0=he1b5a44_1001
  - libgomp=11.2.0=h1234567_1
  - libiconv=1.17=h166bdaf_0
  - liblapack=3.9.0=16_linux64_openblas
  - libnetcdf=4.8.1=nompi_hb3fd0d9_101
  - libnghttp2=1.46.0=hce63b2e_0
  - libopenblas=0.3.21=h043d6bf_0
  - libpng=1.6.37=h21135ba_2
  - libssh2=1.10.0=ha56f1ee_2
  - libstdcxx-ng=11.2.0=h1234567_1
  - libtiff=4.3.0=hf544144_1
  - libwebp-base=1.2.2=h7f98852_1
  - libxcb=1.13=h7f98852_1004
  - libxml2=2.9.12=h72842e0_0
  - libzip=1.8.0=h4de3113_1
  - lz4-c=1.9.3=h9c3ff4c_1
  - ncurses=6.4=h6a678d5_0
  - netcdf4=1.5.8=nompi_py39h64b754b_101
  - numpy=1.22.3=py39hc58783e_2
  - openssl=1.1.1o=h166bdaf_0
  - ossuuid=1.6.2=hf484d3e_1000
  - pbr=6.1.1=pyhd8ed1ab_1
  - pip=25.0=py39h06a4308_0
  - proj=8.2.1=h277dcde_0
  - pthread-stubs=0.4=h36c2ea0_1001
  - python=3.9.7=hb7a2778_3_cpython
  - python_abi=3.9=5_cp39
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - six=1.17.0=pyhd8ed1ab_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - udunits2=2.2.28=hc3e0081_0
  - wheel=0.45.1=py39h06a4308_0
  - xorg-fixesproto=5.0=h7f98852_1002
  - xorg-inputproto=2.3.2=h7f98852_1002
  - xorg-kbproto=1.0.7=h7f98852_1002
  - xorg-libx11=1.7.2=h7f98852_0
  - xorg-libxau=1.0.9=h7f98852_0
  - xorg-libxdmcp=1.1.3=h7f98852_0
  - xorg-libxext=1.3.4=h7f98852_1
  - xorg-libxfixes=5.0.3=h7f98852_1004
  - xorg-libxi=1.7.10=h7f98852_0
  - xorg-xextproto=7.3.0=h7f98852_1002
  - xorg-xproto=7.0.31=h7f98852_1007
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - zstd=1.5.0=ha95c52a_0
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - commonmark==0.9.1
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - packaging==24.2
      - pluggy==1.5.0
      - pygments==2.19.1
      - pytest==8.3.5
      - recommonmark==0.7.1
      - requests==2.32.3
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - urllib3==2.3.0
      - zipp==3.21.0
prefix: /opt/conda/envs/nccompress

test/test_nc2nc.py::test_nc2nc
test/test_nc2nc.py::test_numvals test/test_nc2nc.py::test_cascadeRounding test/test_nc2nc.py::test_calcChunkShape test/test_nc2nc.py::test_chunk_shape_nD
nccompress/nc2nc.py nccompress/nccompress.py
nccompress/nc2nc.py nccompress/nccompress.py