diff --git a/src/composer/cli/blueprints.py b/src/composer/cli/blueprints.py
index d4fc33b7..1872e2fe 100644
--- a/src/composer/cli/blueprints.py
+++ b/src/composer/cli/blueprints.py
@@ -72,7 +72,7 @@ def blueprints_list(socket_path, api_version, args, show_json=False):
     blueprints list
     """
     api_route = client.api_url(api_version, "/blueprints/list")
-    result = client.get_url_json(socket_path, api_route)
+    result = client.get_url_json_unlimited(socket_path, api_route)
     (rc, exit_now) = handle_api_result(result, show_json)
     if exit_now:
         return rc
@@ -119,7 +119,7 @@ def blueprints_changes(socket_path, api_version, args, show_json=False):
     blueprints changes <blueprint,...>     Display the changes for each blueprint.
     """
     api_route = client.api_url(api_version, "/blueprints/changes/%s" % (",".join(argify(args))))
-    result = client.get_url_json(socket_path, api_route)
+    result = client.get_url_json_unlimited(socket_path, api_route)
     (rc, exit_now) = handle_api_result(result, show_json)
     if exit_now:
         return rc
diff --git a/src/composer/cli/modules.py b/src/composer/cli/modules.py
index cd377838..0a775738 100644
--- a/src/composer/cli/modules.py
+++ b/src/composer/cli/modules.py
@@ -37,7 +37,7 @@ def modules_cmd(opts):
         return 1
 
     api_route = client.api_url(opts.api_version, "/modules/list")
-    result = client.get_url_json(opts.socket, api_route)
+    result = client.get_url_json_unlimited(opts.socket, api_route)
     (rc, exit_now) = handle_api_result(result, opts.json)
     if exit_now:
         return rc
diff --git a/src/composer/cli/projects.py b/src/composer/cli/projects.py
index 39c56085..f2a5b683 100644
--- a/src/composer/cli/projects.py
+++ b/src/composer/cli/projects.py
@@ -59,7 +59,7 @@ def projects_list(socket_path, api_version, args, show_json=False):
     projects list
     """
     api_route = client.api_url(api_version, "/projects/list")
-    result = client.get_url_json(socket_path, api_route)
+    result = client.get_url_json_unlimited(socket_path, api_route)
     (rc, exit_now) = handle_api_result(result, show_json)
     if exit_now:
         return rc
diff --git a/src/composer/http_client.py b/src/composer/http_client.py
index ebbac2af..ff356bbf 100644
--- a/src/composer/http_client.py
+++ b/src/composer/http_client.py
@@ -20,6 +20,7 @@ log = logging.getLogger("composer-cli")
 import os
 import sys
 import json
+from urlparse import urlparse, urlunparse
 
 from composer.unix_socket import UnixHTTPConnectionPool
 
@@ -35,6 +36,29 @@ def api_url(api_version, url):
     """
     return os.path.normpath("/api/v%s/%s" % (api_version, url))
 
+def append_query(url, query):
+    """Add a query argument to a URL
+
+    The query should be of the form "param1=what&param2=ever", i.e., no
+    leading '?'. The new query data will be appended to any existing
+    query string.
+
+    :param url: The original URL
+    :type url: str
+    :param query: The query to append
+    :type query: str
+    :returns: The new URL with the query argument included
+    :rtype: str
+    """
+
+    url_parts = urlparse(url)
+    if url_parts.query:
+        new_query = url_parts.query + "&" + query
+    else:
+        new_query = query
+    return urlunparse([url_parts[0], url_parts[1], url_parts[2],
+                       url_parts[3], new_query, url_parts[5]])
+
 def get_url_raw(socket_path, url):
     """Return the raw results of a GET request
 
@@ -69,6 +93,31 @@ def get_url_json(socket_path, url):
     r = http.request("GET", url)
     return json.loads(r.data.decode('utf-8'))
 
+def get_url_json_unlimited(socket_path, url):
+    """Return the JSON results of a GET request
+
+    For URLs that use offset/limit arguments, this command will
+    fetch all results for the given request.
+
+    :param socket_path: Path to the Unix socket to use for API communication
+    :type socket_path: str
+    :param url: URL to request
+    :type url: str
+    :returns: The json response from the server
+    :rtype: dict
+    """
+    http = UnixHTTPConnectionPool(socket_path)
+
+    # Start with limit=0 to just get the number of objects
+    total_url = append_query(url, "limit=0")
+    r_total = http.request("GET", total_url)
+    json_total = json.loads(r_total.data.decode('utf-8'))
+
+    # Add the "total" returned by limit=0 as the new limit
+    unlimited_url = append_query(url, "limit=%d" % json_total["total"])
+    r_unlimited = http.request("GET", unlimited_url)
+    return json.loads(r_unlimited.data.decode('utf-8'))
+
 def delete_url_json(socket_path, url):
     """Send a DELETE request to the url and return JSON response