function driver (url, authToken, config = {}) {
  assertString(url, 'Bolt URL')
  const parsedUrl = urlUtil.parseDatabaseUrl(url)

  // Determine encryption/trust options from the URL.
  let routing = false
  let encrypted = false
  let trust
  switch (parsedUrl.scheme) {
    case 'bolt':
      break
    case 'bolt+s':
      encrypted = true
      trust = 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'
      break
    case 'bolt+ssc':
      encrypted = true
      trust = 'TRUST_ALL_CERTIFICATES'
      break
    case 'neo4j':
      routing = true
      break
    case 'neo4j+s':
      encrypted = true
      trust = 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'
      routing = true
      break
    case 'neo4j+ssc':
      encrypted = true
      trust = 'TRUST_ALL_CERTIFICATES'
      routing = true
      break
    default:
      throw new Error(`Unknown scheme: ${parsedUrl.scheme}`)
  }

  // Encryption enabled on URL, propagate trust to the config.
  if (encrypted) {
    // Check for configuration conflict between URL and config.
    if ('encrypted' in config || 'trust' in config) {
      throw new Error(
        'Encryption/trust can only be configured either through URL or config, not both'
      )
    }
    config.encrypted = ENCRYPTION_ON
    config.trust = trust
    config.clientCertificate = resolveCertificateProvider(config.clientCertificate)
  }

  const authTokenManager = createAuthManager(authToken)

  // Use default user agent or user agent specified by user.
  config.userAgent = config.userAgent || USER_AGENT
  config.boltAgent = internal.boltAgent.fromVersion(VERSION)
  const address = ServerAddress.fromUrl(parsedUrl.hostAndPort)

  const meta = {
    address,
    typename: routing ? 'Routing' : 'Direct',
    routing
  }

  return new Driver(meta, config, createConnectionProviderFunction())

  function createConnectionProviderFunction () {
    if (routing) {
      return (id, config, log, hostNameResolver) =>
        new RoutingConnectionProvider({
          id,
          config,
          log,
          hostNameResolver,
          authTokenManager,
          address,
          userAgent: config.userAgent,
          boltAgent: config.boltAgent,
          routingContext: parsedUrl.query
        })
    } else {
      if (!isEmptyObjectOrNull(parsedUrl.query)) {
        throw new Error(
          `Parameters are not supported with none routed scheme. Given URL: '${url}'`
        )
      }

      return (id, config, log) =>
        new DirectConnectionProvider({
          id,
          config,
          log,
          authTokenManager,
          address,
          userAgent: config.userAgent,
          boltAgent: config.boltAgent
        })
    }
  }
}
Construct a new Neo4j Driver. This is your main entry point for this
library.

@param {string} url The URL for the Neo4j database, for instance "neo4j://localhost" and/or "bolt://localhost"
@param {Map<string,string>} authToken Authentication credentials. See {@link auth} for helpers.
@param {Config} config Configuration object.
@returns {Driver}